Sau hướng dẫn cuối cùng của chúng tôi trên blog Upstash đã giành được một vị trí trên bản tin Bytes , Tôi nghĩ chúng ta sẽ tiếp tục bữa tiệc SvelteKit.
Là một người hâm mộ cuồng nhiệt của Svelte, tôi ngày càng thấy ngày càng có nhiều người tham gia — và điều đó khiến tôi vô cùng phấn khích về tương lai.
Một trong những công cụ vẫn chưa được chú ý là Lucia.
Trong hướng dẫn này, tôi sẽ chỉ cho bạn cách thiết lập và chạy xác thực với Lucia. Chúng tôi sẽ sử dụng PlanetScale cho nhu cầu cơ sở dữ liệu của mình và Upstash Redis để xử lý các phiên.
Dưới đây là ảnh chụp màn hình mục tiêu cuối cùng của chúng tôi cho hướng dẫn này. Bạn có thể tìm thấy kho lưu trữ ví dụ tại đây.

Hướng dẫn này sẽ có trong SvelteKit, nhưng vì Lucia hỗ trợ bất kỳ khung nào nên hầu hết hướng dẫn này có thể dễ dàng áp dụng cho bất kỳ khung phổ biến nào hiện có.
Lucia là gì?
Nói một cách đơn giản, Lucia là một thư viện dành cho TypeScript giúp việc xử lý người dùng và phiên trở nên dễ dàng. Ban đầu, thư viện này được tạo cho SvelteKit, nhưng nó đã liên tục phát triển và hiện đủ linh hoạt để hoạt động tốt với hầu hết mọi khung công tác.
Điều tuyệt vời ở Lucia là cách nó trang bị cho bạn mọi thứ bạn cần để quản lý sự phức tạp của quá trình xác thực mà không làm ảnh hưởng đến trải nghiệm người dùng. Hãy coi Lucia như một tập hợp những nguyên thủy — việc bạn muốn cấu trúc mã và xử lý trải nghiệm người dùng như thế nào là tùy thuộc vào bạn. Lucia có một số phần chính mà bạn cần phải hiểu:
Phần mềm trung gian cho phép Lucia đọc yêu cầu và phản hồi đối với các khung và thời gian chạy khác nhau.
Đây là ví dụ về cách bạn định cấu hình phần mềm trung gian:
import { lucia } from "lucia";
import { node } from "lucia/middleware";
// import { nextjs } from "lucia/middleware";
// import { h3 } from "lucia/middleware";
export const auth = lucia({
env: "DEV", // "PROD" if deployed to HTTPS
middleware: node(),
}); Bộ điều hợp cơ sở dữ liệu cho phép Lucia lưu trữ và truy xuất người dùng và phiên. Bằng cách cung cấp một bộ chuyển đổi, Lucia biết cách truy vấn những loại này. Có 2 loại bộ điều hợp; bộ điều hợp thông thường và bộ điều hợp phiên. Trong hướng dẫn cụ thể này, chúng tôi sẽ sử dụng cơ sở dữ liệu mySQL được lưu trữ trên PlanetScale để lưu trữ người dùng và phiên bản Redis được lưu trữ trên Upstash để xử lý các phiên.
Đây là ví dụ về cách bạn định cấu hình bộ điều hợp cơ sở dữ liệu:
import { prisma } from "@lucia-auth/adapter-prisma";
import { PrismaClient } from "@prisma/client";
import { lucia } from "lucia";
const client = new PrismaClient();
const auth = lucia({
env: "DEV",
adapter: prisma(client),
}); Với thông tin cơ bản đó, hãy bắt đầu ngay.
Điều kiện tiên quyết
Để thiết lập và chạy ứng dụng cũng như làm theo, bạn cần:
- Hiểu biết cơ bản về SvelteKit. Xử lý biểu mẫu và định tuyến là một điểm cộng.
- Làm quen cơ bản với Drizzle ORM.
- Tài khoản và cơ sở dữ liệu trên PlanetScale.
- Truy cập vào phiên bản Redis chẳng hạn như Upstash Redis.
Bắt đầu
Vì mục đích hiệu quả, chúng tôi sẽ không tạo toàn bộ ứng dụng từ đầu.
Thay vào đó, bạn có thể sao chép sveltekit-lucia-redis thư mục từ kho ví dụ Upstash để theo dõi.
Sau khi tải xuống kho lưu trữ, hãy điều hướng vào ứng dụng bằng cd ra lệnh và cài đặt các phần phụ thuộc thông qua trình quản lý gói ưa thích của bạn và đặt .env các biến bằng cách sao chép .env.example .
Tìm hiểu các phần chính
Dưới đây là tóm tắt nhanh tất cả các phần quan trọng.
src/lib/server/auth/index.ts- Đây là nơi chúng tôi định cấu hình Lucia.src/lib/server/drizzle- Drizzle giúp chúng ta dễ dàng tạo một lược đồ mySQL mà chúng ta có thể đẩy lên PlanetScale một cách thuận tiện bằng cách sử dụng Drizzle Kit.src/lib/server/planetscale- Xuất Ứng dụng khách Upstash mà chúng tôi sử dụng trong cấu hình bộ điều hợp Lucia để quản lý người dùng.src/lib/server/upstash- Xuất Ứng dụng khách Upstash mà chúng tôi sử dụng trong cấu hình bộ điều hợp Lucia để quản lý phiên.
Chia nhỏ mã
Định cấu hình Lucia
Điều đầu tiên chúng ta cần làm là cấu hình Lucia. Chúng ta có thể thực hiện việc này bằng cách tạo một tệp mới trong src/lib/server/auth/index.ts .
import { planetscale } from "@lucia-auth/adapter-mysql";
import { dev } from "$app/environment";
import { lucia } from "lucia";
import { sveltekit } from "lucia/middleware";
import { ps } from "../planetscale";
export enum PROVIDER_ID {
EMAIL = "email",
}
export const auth = lucia({
adapter: {
user: planetscale(ps, {
user: "users",
key: "keys",
/**
* Sessions are handled by Upstash Redis.
*/
session: null,
}),
},
middleware: sveltekit(),
env: dev ? "DEV" : "PROD",
getUserAttributes: (data) => {
return {
userId: data.id,
email: data.email,
};
},
});
export type Auth = typeof auth; Sau đây là tóm tắt nhanh những gì đang diễn ra ở đây:
Chúng tôi nhập lucia chức năng từ lucia gói thiết lập cấu hình cho Lucia.
Điều đầu tiên chúng ta làm là định cấu hình adapter tài sản. Đây là nơi chúng tôi hướng dẫn Lucia cách xử lý người dùng và phiên.
Chúng tôi đặt thuộc tính phiên thành null vì chúng tôi muốn sử dụng Redis để xử lý các phiên. Nếu bạn sử dụng chuỗi 'session' thay vào đó, ở đây, Lucia sẽ sử dụng cùng một bộ chuyển đổi cho cả người dùng và phiên (các chuỗi này tương ứng với các bảng trong cơ sở dữ liệu của bạn).
Đừng lo lắng về bộ điều hợp phiên bây giờ, chúng ta sẽ giải quyết vấn đề đó sau.
Trong middleware chúng ta có thể cho Lucia biết rằng chúng ta đang sử dụng SvelteKit. Điều này sẽ cho phép Lucia đọc các đối tượng yêu cầu và phản hồi.
Hãy lưu ý đến Auth đã xuất loại. Đây là loại auth của chúng tôi đối tượng. Chúng tôi sẽ cần điều này để thiết lập SvelteKit cục bộ.
Có được khả năng suy luận kiểu tuyệt vời với Lucia
Lucia được viết bằng TypeScript, vì vậy bạn sẽ có được suy luận kiểu tuyệt vời ngay lập tức. Hãy đảm bảo SvelteKit biết về Auth loại chúng tôi vừa tạo.
Mở app.d.ts của bạn tập tin và thêm vào như sau:
import type { Auth as LuciaAuth } from "$lib/server/auth";
import type { AuthRequest, Session, User } from "lucia";
declare global {
namespace App {
// interface Error {}
interface Locals {
auth: AuthRequest;
session: Session | null;
}
interface PageData {
user?: User;
}
// interface Platform {}
}
}
/// <reference types="lucia" />
declare global {
namespace Lucia {
type Auth = LuciaAuth;
type DatabaseUserAttributes = {
email: string;
};
type DatabaseSessionAttributes = {};
}
}
export {};
Bằng cách thêm Auth gõ vào Lucia không gian tên, bây giờ chúng ta có thể truy cập vào auth đối tượng từ locals đối tượng trong các tuyến SvelteKit của chúng tôi.
Nhưng bất cứ thứ gì được nhập từ Lucia giờ đây cũng sẽ có đúng loại.
Bây giờ chúng ta có những loại này, chúng ta có thể thiết lập hooks.server.ts . Đây là nơi chúng ta sẽ liên kết AuthRequest và Session phản đối yêu cầu hiện tại.
Điều này sẽ giúp nó có thể truy cập dễ dàng trên máy chủ thông qua locals .
import type { Handle } from "@sveltejs/kit";
import { sequence } from "@sveltejs/kit/hooks";
import { auth } from "$lib/server";
const auth_handle: Handle = async ({ event, resolve }) => {
event.locals.auth = auth.handleRequest(event);
event.locals.session = await event.locals.auth.validate();
return resolve(event);
};
export const handle = sequence(auth_handle);
Chúng tôi cũng sẽ nhập sequence đây là một hàm trợ giúp cho phép chúng ta chạy nhiều hook theo trình tự. Điều này sẽ hữu ích sau này khi chúng ta cố gắng bảo vệ các tuyến đường của mình.
Tạo mô hình người dùng
Bây giờ chúng ta đã định cấu hình Lucia, chúng ta có thể tạo mô hình người dùng của mình.
Chúng tôi sẽ sử dụng Drizzle ORM vì hiện tại nó đang rất nóng và đang diễn ra.

Và meme của họ đã đúng. Chỉ cần nhìn vào cái này.
Trước khi có thể tiếp tục, bạn cần tạo cơ sở dữ liệu trên PlanetScale. Và thiết lập tập tin cấu hình Mưa phùn. Điều này sẽ giúp Drizzle CLI kết nối với cơ sở dữ liệu của bạn.
drizzle.config.tsimport dotenv from "dotenv";
import type { Config } from "drizzle-kit";
dotenv.config();
const username = process.env.DATABASE_USERNAME;
const password = process.env.DATABASE_PASSWORD;
const host = process.env.DATABASE_HOST;
const db = process.env.DATABASE_NAME;
const connectionString = `mysql://${username}:${password}@${host}/${db}?ssl={"rejectUnauthorized":true}`;
export default {
schema: "./src/lib/server/drizzle/schema/index.ts",
driver: "mysql2",
dbCredentials: {
connectionString: connectionString,
},
} satisfies Config; Vì chúng tôi đang sử dụng bộ điều hợp mySQL nên Lucia mong muốn mô hình người dùng của chúng tôi có cấu trúc cụ thể. Bạn có thể tìm thêm thông tin về vấn đề này trong tài liệu.
Đặt đoạn mã sau vào src/lib/server/drizzle/schema/index.ts .
import { relations } from "drizzle-orm";
import {
bigint,
datetime,
index,
int,
mysqlEnum,
mysqlTable,
timestamp,
unique,
varchar,
} from "drizzle-orm/mysql-core";
export const users = mysqlTable(
"users",
{
id: varchar("id", { length: 255 }).primaryKey(),
createdAt: timestamp("createdAt").defaultNow().onUpdateNow().notNull(),
updatedAt: timestamp("updatedAt").defaultNow().onUpdateNow().notNull(),
email: varchar("email", { length: 191 }).notNull(),
},
(table) => {
return {
idIdx: index("users_id_idx").on(table.id),
userIdKey: unique("users_id_key").on(table.id),
};
},
);
export const keys = mysqlTable(
"keys",
{
id: varchar("id", { length: 255 }).primaryKey(),
hashedPassword: varchar("hashed_password", { length: 255 }),
userId: varchar("user_id", { length: 255 }).notNull(),
},
(table) => {
return {
userIdIdx: index("keys_user_id_idx").on(table.userId),
keyIdKey: unique("keys_id_key").on(table.id),
};
},
);
Và chạy pnpm drizzle-kit push:mysql để đẩy lược đồ lên PlanetScale.
Thì đấy! Bây giờ bạn đã có mô hình người dùng mà Lucia có thể sử dụng để quản lý người dùng.
Thiết lập quản lý phiên
Bây giờ chúng ta đã có mô hình người dùng, chúng ta có thể thiết lập quản lý phiên.
Chúng tôi sẽ sử dụng Upstash Redis để xử lý các phiên. Bạn có thể đăng ký tài khoản miễn phí tại đây.

Khi đã vào trang tổng quan, tất cả những gì bạn cần làm là tạo cơ sở dữ liệu mới và sao chép các biến môi trường.

Bây giờ hãy thêm các biến này vào .env của bạn tập tin. Và thêm dòng sau vào src/lib/server/upstash/index.ts .
import { Redis } from "@upstash/redis";
import {
UPSTASH_REDIS_REST_TOKEN,
UPSTASH_REDIS_REST_URL,
} from "$env/static/private";
export const upstashClient = new Redis({
url: UPSTASH_REDIS_REST_URL,
token: UPSTASH_REDIS_REST_TOKEN,
});
Bây giờ hãy nhớ khi định cấu hình Lucia, chúng tôi đã đặt session tới null . Điều này là do chúng tôi muốn sử dụng Redis để xử lý các phiên. Cấu hình của chúng ta bây giờ trông như thế này:
import { planetscale } from "@lucia-auth/adapter-mysql";
import { upstash } from "@lucia-auth/adapter-session-redis";
import { dev } from "$app/environment";
import { lucia } from "lucia";
import { sveltekit } from "lucia/middleware";
import { ps } from "../planetscale";
import { upstashClient } from "../upstash";
export enum PROVIDER_ID {
EMAIL = "email",
}
export const auth = lucia({
adapter: {
user: planetscale(ps, {
user: "users",
key: "keys",
session: null,
}),
// Instruct Lucia to use Upstash Redis for sessions
session: upstash(upstashClient),
},
middleware: sveltekit(),
env: dev ? "DEV" : "PROD",
getUserAttributes: (data) => {
return {
userId: data.id,
email: data.email,
};
},
});
export type Auth = typeof auth; Thật may mắn cho chúng tôi, Lucia có sẵn bộ chuyển đổi Upstash Redis. Vì vậy, tất cả những gì chúng ta cần làm là nhập nó và chuyển nó sang ứng dụng khách Upstash.
Giờ thì thật dễ dàng!
Tạo tuyến đường
Bây giờ chúng ta đã định cấu hình Lucia, chúng ta có thể tạo các tuyến đường của mình.
Tạo các thư mục sau trong src/routes . Bây giờ đừng lo lắng về bất kỳ tệp nào, chúng ta sẽ xem xét chúng một chút.
src/routes/authsrc/routes/auth/signinsrc/routes/auth/signup
src/routes/app
Mẹo: Việc có một số "tính năng" nhất định trong cùng tên thư mục hoặc nhóm giúp bạn dễ dàng quản lý khi thực hiện chuyển hướng và bảo vệ các tuyến đường.
Tạo trang đăng nhập
Cuối cùng, chúng ta có thể thực hiện một số công việc ở mặt trước! Hãy bắt đầu với trang đăng nhập.
Tạo một tệp mới trong src/routes/auth/signin/+page.svelte . Bây giờ tôi sẽ bỏ qua kiểu dáng và tập trung vào chức năng — nhưng bạn có thể tìm thấy mã đầy đủ trong kho lưu trữ ví dụ.
<script lang="ts">
import { enhance } from '$app/forms';
import { Button, Input, Label, PasswordInput } from '$lib/components/common';
import type { ActionData } from './$types';
export let form: ActionData;
let loading = false;
let email = '';
let password = '';
</script>
<form
method="POST"
use:enhance={() => {
loading = true;
return async ({ update }) => {
loading = false;
update();
};
}}
>
{#if form && form.error}
<div class="p-2 mb-4 text-sm text-center text-red-900 bg-red-200 rounded-sm">
Error: {form.error}
</div>
{/if}
<div class="grid gap-2.5">
<div class="grid gap-1">
<Label for="email">Email</Label>
<Input
bind:value={email}
name="email"
placeholder="Email"
type="email"
autoCapitalize="none"
autoComplete="email"
autoCorrect="off"
required={true}
/>
</div>
<div class="grid gap-1">
<Label for="password">Password</Label>
<PasswordInput name="password" placeholder="Password" bind:value={password} />
</div>
<div class="mt-6 col-span-full">
<Button type="submit" class="w-full" disabled={loading}>
{#if loading}
Loading...
{:else}
Sign in
{/if}
</Button>
</div>
</div>
</form>
use:enhance hành động sẽ dần dần nâng cao biểu mẫu và cho phép chúng tôi hiển thị trạng thái tải khi biểu mẫu được gửi. Bạn có thể đọc thêm về nâng cao tại đây.
Phần còn lại của mã khá dễ hiểu.
Xử lý yêu cầu đăng nhập
SvelteKit khiến việc xử lý các yêu cầu POST trở nên vô cùng dễ dàng. Tất cả những gì chúng ta cần làm là tạo một tệp +page.server.ts trong cùng thư mục với +page.svelte tập tin và xuất actions đối tượng có ít nhất default tài sản.
import { fail, redirect } from "@sveltejs/kit";
import { auth, PROVIDER_ID } from "$lib/server";
import { LuciaError } from "lucia";
import type { Actions, PageServerLoad } from "./$types";
export const actions = {
/* our actions here */
}; Hãy cùng khám phá các thành phần chính trong phần này của tệp:
Chúng tôi đã nhập PROVIDER_ID enum và auth từ src/lib/server/auth , mà chúng tôi đã tạo trước đó. auth này đối tượng chứa tất cả các phương thức chúng ta cần để quản lý người dùng và phiên.
Bây giờ chúng ta hãy xem actions đối tượng. Chúng tôi có thể lấy dữ liệu biểu mẫu từ đối tượng yêu cầu và thực hiện một số công việc quản lý cơ bản.
actions = {
default: async ({ request, locals }) => {
const formData = await request.formData();
const email = formData.get("email") as string;
const password = formData.get("password") as string;
const fields = [email, password];
if (fields.some(field => !field)) {
return fail(400, {
error: "All fields are required"
});
} Tiếp theo, chúng tôi sẽ cố gắng đăng nhập người dùng. Nếu người dùng không tồn tại hoặc mật khẩu không chính xác, Lucia sẽ báo lỗi. Chúng tôi đã chuẩn bị cho sự kiện này bằng cách phát hiện lỗi và trả về phản hồi 400 cùng với thông báo lỗi.
try {
const user = await auth.useKey(PROVIDER_ID.EMAIL, email.toLowerCase(), password);
const session = await auth.createSession({
userId: user.userId,
attributes: {}
});
locals.auth.setSession(session);
} catch (err) {
if (
err instanceof LuciaError &&
(err.message === 'AUTH_INVALID_KEY_ID' || err.message === 'AUTH_INVALID_PASSWORD')
) {
return fail(400, {
error: 'Incorrect username of password'
});
}
return fail(400, {
error: 'An unknown error occurred'
});
} Nếu người dùng tồn tại và mật khẩu đúng, chúng tôi sẽ tạo một phiên mới.
Và cuối cùng, chúng tôi sẽ chuyển hướng người dùng đến trang tổng quan.
return redirect('/app'); Như bạn có thể biết, Lucia đã tóm tắt rất nhiều sự phức tạp của việc xác thực. Tất cả những gì chúng ta cần làm là gọi đúng phương thức và Lucia sẽ xử lý phần còn lại.

Không cần băm mật khẩu, tạo phiên hoặc quản lý cookie. Lucia làm tất cả cho chúng tôi. Và tất cả đều an toàn!
Tạo trang đăng ký
Tạo một tệp mới trong src/routes/auth/signup/+page.svelte .
Trang đăng ký rất giống với trang đăng nhập nên không có gì nhiều để giải thích ở đây. Điểm khác biệt duy nhất là chúng tôi yêu cầu xác nhận mật khẩu.
src/routes/auth/signup/+page.svelte<script lang="ts">
import { enhance } from '$app/forms';
import { Button, Input, Label, PasswordInput } from '$lib/components/common';
import type { ActionData } from './$types';
export let form: ActionData;
let loading = false;
let email = '';
let password = '';
let passwordConfirmation = '';
</script>
<form
method="POST"
use:enhance={() => {
loading = true;
return async ({ update }) => {
loading = false;
update();
};
}}
>
{#if form && form.error}
<div class="p-2 mb-4 text-sm text-center text-red-900 bg-red-200 rounded-sm">
Error: {form.error}
</div>
{/if}
<div class="grid gap-2.5">
<div class="grid gap-1">
<Label for="email">Email</Label>
<Input
bind:value={email}
name="email"
placeholder="Email"
type="email"
autoCapitalize="none"
autoComplete="email"
autoCorrect="off"
required={true}
/>
</div>
<div class="grid gap-1">
<Label for="password">Password</Label>
<PasswordInput name="password" placeholder="Password" bind:value={password} />
</div>
<div class="grid gap-1">
<Label for="passwordConfirmation">Confirm password</Label>
<PasswordInput
name="passwordConfirmation"
placeholder="Repeat password"
bind:value={passwordConfirmation}
/>
</div>
<div class="mt-6 col-span-full">
<Button type="submit" class="w-full" disabled={loading}>
{#if loading}
Loading...
{:else}
Sign in
{/if}
</Button>
</div>
</div>
</form> Xử lý yêu cầu đăng ký
Tạo một tệp mới trong src/routes/auth/signup/+page.server.ts .
Để đăng ký, chúng tôi sẽ cần sử dụng mẫu tương tự như với biểu mẫu đăng ký của mình nhưng sẽ có một số khác biệt bắt đầu từ việc truy xuất dữ liệu từ biểu mẫu, xác thực trường cho đến khi tạo người dùng và xử lý những người dùng hiện có.
Quá trình nhập giống như với trang đăng nhập, vì vậy chúng tôi sẽ bỏ qua phần đó.
Chúng ta sẽ bắt đầu bằng cách lấy dữ liệu biểu mẫu từ đối tượng yêu cầu và thực hiện một số công việc quản lý cơ bản. Chúng tôi cũng sẽ kiểm tra xem mật khẩu có khớp hay không.
const formData = await request.formData();
const email = formData.get('email') as string;
const password = formData.get('password') as string;
const passwordConfirmation = formData.get('passwordConfirmation') as string;
const fields = [email, password, passwordConfirmation];
if (fields.some((field) => !field)) {
return fail(400, {
error: 'All fields are required'
});
}
if (password !== passwordConfirmation) {
return fail(400, {
error: 'Passwords do not match'
});
} Tiếp theo, chúng tôi sẽ cố gắng tìm người dùng qua email bằng cách sử dụng Drizzle ORM. Nếu người dùng tồn tại, chúng tôi sẽ trả về phản hồi 400 cùng với thông báo lỗi.
try {
const user = await db.query.users.findFirst({
where: eq(schema.users.email, email.toLowerCase()),
});
if (user) {
return fail(400, {
error: "User with this email already exists"
});
} Nếu người dùng không tồn tại, chúng tôi sẽ tạo một người dùng mới bằng Lucia.
const newUser = await auth.createUser({
key: {
providerId: PROVIDER_ID.EMAIL,
providerUserId: email.toLowerCase(),
password: password,
},
attributes: {
email,
},
}); Và cuối cùng, chúng ta sẽ tạo một phiên mới và chuyển hướng người dùng đến trang tổng quan.
const session = await auth.createSession({
userId: newUser.userId,
attributes: {},
});
locals.auth.setSession(session); Vắt chanh thật dễ dàng!
Phần thưởng:Tạo trang đăng xuất
Trong khi chúng ta đang ở đó, hãy tạo một điểm cuối để đăng xuất người dùng. Tạo một tệp mới trong src/routes/auth/signout/+server.ts .
Và thêm đoạn mã sau:
src/routes/auth/signout/+server.tsimport { auth } from "$lib/server";
import type { RequestHandler } from "./$types";
export const POST: RequestHandler = async ({ locals }) => {
const session = await locals.auth.validate();
if (!session) {
return new Response(null, {
status: 400,
});
}
// Invalidate session or alternatively, you can delete all sessions: await auth.invalidateAllUserSessions(session.userId);
await auth.invalidateSession(session.sessionId);
// Remove the cookie.
locals.auth.setSession(null);
return new Response(null, {
status: 200,
});
}; Một lần nữa, Lucia lại hỗ trợ chúng tôi bằng cách làm cho các phiên vô hiệu hóa cực kỳ dễ dàng. Tất cả những gì chúng ta cần làm bây giờ là gọi điểm cuối này khi người dùng nhấp vào nút đăng xuất.
src/routes/app/+page.svelte<script lang="ts">
import { goto } from '$app/navigation';
import { Button } from '$lib/components/common';
async function handleSignOut() {
const response = await fetch('/auth/signout', {
method: 'POST',
headers: {
'Content-Type': 'application/json'
}
});
if (response.ok) {
goto('/auth/signin', {
replaceState: true,
invalidateAll: true
});
}
}
</script>
<Button on:click={handleSignOut}>Sign out</Button> Đó là sự kết thúc
Chúng tôi đã tạo thành công xác thực an toàn loại với Lucia, PlanetScale và Upstash Redis. Và chúng ta mới chỉ phác thảo sơ bộ những gì Lucia có thể làm.
Một lần nữa, bạn có thể tìm thấy kho lưu trữ cho hướng dẫn này tại đây. Nếu bạn muốn tìm hiểu thêm về Lucia, tôi thực sự khuyên bạn nên xem tài liệu.
Trước khi tiếp tục, bạn nên tham gia cộng đồng Upstash Discord - chúng ta đang có khoảng thời gian vui vẻ. Và nếu bạn muốn biết thêm nội dung SvelteKit, bạn có thể tìm thấy nội dung đó trên blog của tôi tại đây.