发布于 2026-01-06 2 阅读
0

SvelteKit 变更:Cookie 和身份验证

SvelteKit 变更:Cookie 和身份验证

介绍

本文将探讨 SvelteKit 中的 cookie,并学习在 SvelteKitgetSession从 hooks 中移除 cookie 处理程序后,如何使用 cookie 进行身份验证。现在我们只能使用新route systemcookies方法。本文将介绍 SvelteKit 中两种不同的用户身份验证方法。

  1. parent()在路由中使用函数。
  2. 使用 Svelte 商店处理身份验证。

曲奇饼

Cookies 是 SvelteKit 中引入的一种用于处理 cookie 标头的新方法。您可以使用此方法轻松地在 Web 应用程序中处理 cookie。此外,还有一些其他方法,例如 `cookies.get_cookie()`cookies和 `cookies.get_cookie( set) get` delete

  • 设置方法

此方法会设置一个 cookie。这会set-cookie在响应中添加一个标头,同时也会使 cookiecookies.get在当前请求期间可用。

默认情况下启用httpOnly`and`选项,如果您希望客户端 JavaScript 读取 cookie 和/或通过 HTTP 传输 cookie,则必须显式禁用这些选项。`option`选项的默认值为 `true` securetruesameSitelax

默认情况下,pathcookie 的路径是当前路径名的“目录”。大多数情况下,您应该显式设置路径path: '/',以使 cookie 在整个应用程序中可用。

设置方法接受三个参数namevalue选项options是可选的,所以你可以自行设置。

cookies.set('session', user.entityId, {
            path: '/',
            httpOnly: true,
            sameSite: 'strict',
            secure: !dev,
            maxAge: 60 * 60 * 24 * 30
        });
Enter fullscreen mode Exit fullscreen mode

在这里,我使用方法在标头中set设置cookie ,并根据需要定义选项。sessionSet-Cookie

1. name : session (string)
2. value : user.entityId (string)
3. options: {
            path: '/',
            httpOnly: true,
            sameSite: 'strict',
            secure: !dev,
            maxAge: 60 * 60 * 24 * 30
        }
Enter fullscreen mode Exit fullscreen mode
  • 获取方法

此方法用于获取先前通过cookies.set或从请求标头中设置的 cookie。

Get 方法接受两个参数nameoptions选项是可选的。

const session = cookies.get('session');
Enter fullscreen mode Exit fullscreen mode

在这里,我使用方法从上面使用方法设置的值中get获取我的sessioncookiesset

  • 删除方法

此方法用于删除 cookie,方法是将 cookie 的值设置为空字符串,并将过期日期设置为过去的日期。

删除方法接受两个参数nameoptions选项是可选的。

await cookies.delete('session');
Enter fullscreen mode Exit fullscreen mode

这就是删除 cookie 所需的全部步骤。

  • 序列化方法

它与 set 方法相同,该方法将 cookie 名称-值对序列化为 Set-Cookie 标头字符串。

Sveltekit 中的身份验证流程

在这里,我将解释如何使用 cookie 和 session 来验证用户身份的步骤。

  1. 所有用户身份验证都始于注册方法之后。因此,首先要确保数据库中已注册用户。

  2. 创建一个登录路由来处理用户身份验证。在这里,我们将使用 set 方法设置名为“session”的 Cookie。

  3. 我们将更新我们hooks.server.ts访问cookies和获取sessioncookie 的方式,使用 get 方法。

  4. 我们将基于会话获取用户,并向locals该用户添加数据。

  5. 接下来+layout.server.js,我们将访问我们的locals数据并返回用户数据。

  6. 我们可以使用这些用户数据来设置身份验证的存储,或者按parent方法使用它。

定义 event.locals 的本地接口,可以在钩子(handle 和 handleError)、仅限服务器的加载函数和 +server.js 文件中访问。

使用 parent() 方法进行身份验证

现在我们将按照流程来编写身份验证流程的代码。

  • 创建一个路由来处理登录。它应该包含 `<username>` 和 `<username>`+page.svelte字段+page.server.js+page.svelte你需要在其中添加你的login form`<username>`email和 ` password<username>` 字段。登录时,它会调用一个 `<username>` 事件处理程序,form action目前+page.server.js这是我们的默认操作。
// +page.server.ts (inside login route)

import { redirect } from '@sveltejs/kit';
import type { PageServerLoad, Actions } from './$types';
import { customResponse } from '$lib/utils';
import { userRepository } from '$lib/Redis/dbRepository';
import * as bcrypt from 'bcrypt';
import { dev } from '$app/environment';

export const actions = {
    default: async ({ request, cookies }) => {
        const form = await request.formData();
        const email = form.get('email');
        const password = form.get('password');

        if (!email || !password) return customResponse(400, false, 'Email and Password are required');

        if (typeof email !== 'string' || typeof password !== 'string')
            return customResponse(400, false, 'Enter a valid email and password.');

        const user = await userRepository.search().where('email').equals(email).return.first();
        const passwordMatch = user && (await bcrypt.compare(password, user.password));

        if (!user || !passwordMatch)
            return customResponse(400, false, 'You entered the wrong credentials.');
        cookies.set('session', user.entityId, {
            path: '/',
            httpOnly: true,
            sameSite: 'strict',
            secure: !dev,
            maxAge: 60 * 60 * 24 * 30
        });
        // return customResponse(200, true, 'User loggedIn successfully');
        throw redirect(307, '/dashboard');
    }
};

// customResponse function from lib/utils

import { invalid } from '@sveltejs/kit';

export const customResponse = (status: number, success: boolean, message: string, data?: any) => {
    if (success) {
        return {
            success: success,
            message: message,
            info: data
        };
    }
    return invalid(status, {
        success: success,
        message: message,
        info: data
    });
};
Enter fullscreen mode Exit fullscreen mode

在这里,我正在验证用户,验证成功后,我们使用 set 方法来设置session cookie

cookies.set('session', user.entityId, {
            path: '/',
            httpOnly: true,
            sameSite: 'strict',
            secure: !dev,
            maxAge: 60 * 60 * 24 * 30
        });
Enter fullscreen mode Exit fullscreen mode
  • 现在我们将利用我们的技术,hook.server.ts在需要时向每条路线提供用户数据。
// hook.server.ts

import type { Handle } from '@sveltejs/kit';
import { userRepository } from './lib/Redis/dbRepository';

// custom redirect from joy of code `https://github.com/JoysOfCode/sveltekit-auth-cookies/blob/migration/src/hooks.ts`
function redirect(location: string, body?: string) {
    return new Response(body, {
        status: 303,
        headers: { location }
    });
}

const unProtectedRoutes: string[] = [
    '/',
    '/login',
    '/createAdmin',
    '/features',
    '/docs',
    '/deployment'
];

export const handle: Handle = async ({ event, resolve }) => {
    const session = event.cookies.get('session');
    if (!session && !unProtectedRoutes.includes(event.url.pathname))
        return redirect('/login', 'No authenticated user.');
    const currentUser = await userRepository.fetch(session as string);

    if (currentUser) {
        event.locals.user = {
            isAuthenticated: true,
            name: currentUser.name,
            email: currentUser.email,
            type: currentUser.user_type,
            active: currentUser.active,
            phone: currentUser.phone
        };
    } else {
        if (!unProtectedRoutes.includes(event.url.pathname)) return redirect('/', 'Not a valid user');
    }

    return resolve(event);
};
Enter fullscreen mode Exit fullscreen mode

在这里,我们将使用该方法访问我们的sessioncookie getconst session = event.cookies.get('session');

之后我们需要检查sessioncookie 是否存在,并且我们添加了额外的路由检查条件,因为如果用户未登录,我们将进行重定向。

为什么要添加这个额外的路由检查条件?这是因为当用户位于login某个路由上,而该用户未获得授权时,我们会将其重定向到login一个页面,这将造成无限重定向循环,而我们的浏览器不喜欢这种情况。

验证完成后,我们将从数据库中获取用户并更新本地设置。

event.locals.user = {
            isAuthenticated: true,
            name: currentUser.name,
            email: currentUser.email,
            type: currentUser.user_type,
            active: currentUser.active,
            phone: currentUser.phone
        };
Enter fullscreen mode Exit fullscreen mode
  • 现在,我们将访问本地服务器+layout.server.js,并将本地用户数据返回到我们的 Web 应用程序。
// +layout.server.js

export const load = async ({ request, locals, cookies }) => {

    return {
        user: locals.user
    };
};
Enter fullscreen mode Exit fullscreen mode

在这里,我们访问本地数据,然后将其返回到所有页面,因为布局如此,所有数据都可供共享相同布局的每个页面访问。

  • 由于parent方法的存在,在路由中访问数据非常容易。我们将使用路由page.jsload方法来访问数据layout
// +page.js

export const load = async ({ parent }) => {
    const { user } = await parent();
    if (user) {
        user: user
    }
};
Enter fullscreen mode Exit fullscreen mode

这将使路由能够访问您的用户数据。第一次使用时可能会觉得复杂,但操作一次后您就会爱上它。

使用商店进行身份验证

在商店里,我们需要一个auth.js文件才能将商店添加到我们的项目中。

除了这里我们不使用parent()方法之外,其他步骤都与上面相同。我们会创建一个存储,然后访问+layout.server.js数据+layout.js,数据会返回给存储+layout.svelte,最后我们将用户数据设置到存储中。

  • 所以请按照所有步骤操作+layout.server.js,并将用户数据返回到所有页面。

  • 然后我们将创建一个商店lib/auth.js

import { writable } from 'svelte/store';
export const user = writable();
Enter fullscreen mode Exit fullscreen mode

这样就足以满足我们门店的需求了。

  • 现在,+layout.js我们将从文件中访问数据+layout.server.js
// `+layout.js`

export const load = async function ({ data }) {
    return {
        user: data.user
    };
};
Enter fullscreen mode Exit fullscreen mode

这将把数据返回到我们的+layout.svelte系统中export let data

// +layout.svelte

<script lang="ts">
  import { user } from "$lib/auth";
  export let data;
  $: $user.set(data.user);
</script>

<slot />
Enter fullscreen mode Exit fullscreen mode

现在我们有了包含用户信息的存储库,并且可以在客户端代码中的任何位置访问它。

这就是我们在 SvelteKit 中使用 cookie 处理身份验证所需的一切。我们还没有讲解如何管理受保护的路由。答案其实已经在本文中有所提及(虽然并不完全准确,但提供了一个处理思路)。你可以稍微思考一下。我可能遗漏了一些内容,或者如果你有任何补充,可以在评论区留言。

资源

最后,我给大家留下一些资源,我写这篇文章时就用到了其中一些。

这是我写给你的。如果你有什么问题或建议,请在评论区留言,也请多多支持❤️。

文章来源:https://dev.to/theether0/sveltekit-changes-session-and-cookies-enb