Version 0.0.2
Last updated: 2023-04-17
Login
Description
After having a good starting point and some inspiration I worked on some login functionality on the website. That way every different user could have the website presented to him in a different way. This tutorial by Joy of Code was recommended to me on how to implement this functionality using cookies and a prisma database. I used this starting point to get familiar with prisma and databases in general.
Changes
The following changes and implementations have been made in that version of the project:
- Installed Prisma and created a client with a SQLite database.
- When user is logged in a cookie is created that saves the current session for 30 days
- Use SvelteKit Hooks to store the session for checking if the user is logged in
To get a better view on how the login functionality works, watch the tutorial.
Features
✅ Login/Register 🧑💻
Code
In here some selected code will be explained more in depth.
schema.prisma file to structure the database
// define database provider that we use
datasource db {
provider = "sqlite"
// url is stored in .env file so that users cant see the url
url = env("DATABASE_URL")
}
// define the database tabels referred to as models
model User {
// unique individual id for each user
id String @id @unique @default(uuid())
// no username can be taken twice
username String @unique
// hash of the password to not store a clear password
passwordHash String
// unique token used for the cookie
userAuthToken String @unique
createdAt DateTime @default(now())
updatedAt DateTime @updatedAt
// assign a role to the user used to seperate users and admins
// using prisma relations to reference the Roles model
// pointing to the id in the Roles model
role Roles @relation(fields: [roleId], references: [id])
roleId Int
}
model Roles {
id Int @id @default(autoincrement())
name String @unique
User User[]
}
login/+page.server.ts to handle the login process
// function to redirect users that are logged away from the login page
export const load: PageServerLoad = async ({ locals }) => {
// redirect user if logged in
if (locals.user) {
throw redirect(302, '/')
}
}
// first we request the username and password from the html form
const username = data.get('username')
const password = data.get('password')
// check if somebody trys to bamboozle us
// if a username/password is not a string or nonexistent fail
if (
typeof username !== 'string' ||
typeof password !== 'string' ||
!username ||
!password
) {
return fail(400, { invalid: true })
}
// if that worked we request the user from the database
const user = await database.user.findUnique({ where: { username } })
// now we also need to import the database on the top
import { database } from '$lib/database'
// now we compare the password entered and the password from the database
const userPassword = await bcrypt.compare(password, user.passwordHash)
// if that fails we return fail and say wrong credentials
return fail(400, {credentials: true})
// if everything went well so far
// we create a new authentification token in the database
const authenticatedUser = await database.user.update({
where: { username: user.username },
data: { userAuthToken: crypto.randomUUID() },
})
// set the cookie to keep the user logged in for one moth
cookies.set('session', authenticatedUser.userAuthToken, {
// send cookie for every page
path: '/',
// server side only cookie so you can't use `document.cookie`
httpOnly: true,
// only requests from same site can send cookies
// https://developer.mozilla.org/en-US/docs/Glossary/CSRF
sameSite: 'strict',
// only sent over HTTPS in production
secure: process.env.NODE_ENV === 'production',
// set cookie to expire after a month
maxAge: 60 * 60 * 24 * 30,
})
Commit: Version 0.0.2
Published: 2023-04-03