介绍
众所周知,Sveltekit上个月发布了V1.0,到目前为止,我们都开始在中型项目中使用它。但是Sveltekit中仍然存在一个疼痛点,该痛点正在管理用户auth和Session。但这不会阻止我们使用Sveltekit。因此,我们能做的就是通过自己的魔法最大程度地减少痛苦,从那里我开始制作一个小包装,使痛苦最小化。让我介绍Sveltekit的新会话管理库,该库是@ethercorps/sveltekit-redis-session
,它将Redis用作Session Manager。我们都知道Redis的速度有多快,甚至Ben Awad
本人都说使用Redis进行会话管理要比其他事情要好得多。我走了那条路,得到了更好的结果,所以我从项目中提取了它并制作了这个包。
资源
先决条件
- Sveltekit项目
- redis客户库for nodejs:
ioredis
// Install in your project root
pnpm i -D ioredis
- 安装
@ethercorps/sveltekit-redis-session
pnpm i -D @ethercorps/sveltekit-redis-session
这个用
ioredis
制成的软件包作为nodejs的主要redis-client,支持异步/等待。
如何使用
我正在使用Typescript,您可以根据您的项目使用JS/TS。
创建和安装所有依赖项后,我们可以从工作开始。
初始化redis会话商店
- 在
lib
目录中创建一个名称sever
的文件夹,然后添加一个文件sessionManager.ts
7
server
目录在lib
中具有特殊的含义。server
目录中的任何文件都只能在服务器端逻辑中使用,这将帮助我们不将某些代码导入客户端。
// lib/server/sessionManager.ts
import { RedisSessionStore } from '@ethercorps/sveltekit-redis-session';
import Redis from 'ioredis';
import { SECRET, REDIS_URL } from '$env/static/private';
// Now we will create new Instance for RedisSessionStore
const options = {
redisClient: new Redis(REDIS_URL)
secret: SECRET
}
// These are the required options to use RedisSessionStore.
export const sessionManager = new RedisSessionStore(options)
SECRET
和REDIS_URL
应该是.env
文件。
SECRET
是不应该被第三方知道的关键。
REDIS_URL
看起来像这个redis://username:password@host:port
,如果您在系统上正在运行redis,REDIS_URL
可能看起来像redis://localhost:6379
。
- RedissessionStore的所有可用选项
// option default explanation
1. redisClient > No Default > Required and Accepts a Redis Client from `ioredis`.
2. secret > No Default > Required and Accepts a string which is supposed to be a secret key.
3. cookieName > Default: `session` > Its the name of cookie which will be added to browser. Accepts a string can we anything you want.
4. prefix > Default: `sk-session:` > A prefix for all the keys added to redis which helps to get all active session with the same prefix. Accept a string can we anything and make a unique prefix which does not exist in redis.
5. signed > Default: true > Signed cookies mean that every key that is added in cookie going to be signed to check if its assigned by us. Its accepts boolean value.
6. encrypted > Default: false > If you want to encrypt your cookies using `aes-256-cbc` algorithm with secret key. Which makes it more secure from tempering. It accepts boolean value.
7. useTTL > Default: true > Redis have a functionality to delete a key automatically from redis after a given time.
// Given time always going to be your maxAge of cookie more on it in cookies options.
8. renewSessionBeforeExpire > Default: false > If you want to renew user session and cookie before expiring automatically you can use it. This works with `renewBeforeSeconds`.
9. renewBeforeSeconds > Default: 30 * 60 > This will update session and cookie before 30 min if user active at that time.
It used in combination of `renewSessionBeforeExpire`. It accept number which is supposed to be seconds as default is 30 minutes.
10. serializer > Default: `JSON` > This is used to stringify data and parse back to data which is supposed to be saved in redis. It accepts
`export type Serializer = {
stringify: Function;
parse: Function;
};`
11. cookiesOptions > Default: defaultCookiesOption
const defaultExpireSeconds: number = 60 * 60 * 24; // One day in seconds
const defaultCookiesOption: CookieSerializeOptions = {
path: '/',
httpOnly: true,
sameSite: 'strict',
secure: !dev,
maxAge: defaultExpireSeconds
}; > It takes any of the parameter accepted by CookieSerializeOptions type from SvelteKit. These options are for setting cookies for the browser.
> In cookiesOptions we have a field `maxAge` which also our time to live(ttl) for redis key expiration time. maxAge accepts time in seconds and which is also in going to be key expire time in redis. //
这些都是RedissessionStore接受的所有选项。
// CookieSerializeOptions type of SvelteKit
export interface CookieSerializeOptions {
domain?: string | undefined;
encode?(value: string): string;
expires?: Date | undefined;
httpOnly?: boolean | undefined;
maxAge?: number | undefined;
path?: string | undefined;
priority?: 'low' | 'medium' | 'high' | undefined;
sameSite?: true | false | 'lax' | 'strict' | 'none' | undefined;
secure?: boolean | undefined;
}
// Learn more about cookieSerializationOptions: https://github.com/DefinitelyTyped/DefinitelyTyped/blob/master/types/cookie/index.d.ts#L14
redissessionStore 上的所有可用方法
redissessionstore 有多种方法,但其中6种对用户有用,其中5种是主要方法和一种支持方法。
每个方法返回{数据:任何,错误:布尔值,消息:字符串}
redissessionstore 的主要方法:
-
createNewsession =>接受(cookie,sessiondata,key?='')。它为Redis添加了一个新的会话,并将Cookie设置为Cookie方法,名称为
'session'
或options.cookieName
。 cookie是来自requestEvent的cookie,sessiondata是dict cookie,它是用于要保存在redis中的数据,如果您不想设置从crypto.randomuuid函数生成的默认随机键,则键是可选的。它在数据中返回{redis键,没有前缀,cookie value}。 -
getsession =>仅接受来自requestEvent的
cookies
。它首先验证基于您的签名或加密方法的cookie。它还检查是否有效更新密钥和cookie到期时间到默认的最大时间,它还检查了续订。它返回您在创建新会话时提供的Redis保存的SessionData。 -
updatesEssionExpiry =>接受requestEvent的cookies方法。它验证cookie,然后更新到会话和cookie的到期。我们已经根据
renewSessionBeforeExpiry
选项处理了基本的自动更新,该选项需要在renewBeforeSeconds
时间范围内使用活动用户请求。这就是为什么当您想更新cookie时,您可以使用此方法添加自己的逻辑。例如。检查用户活动,最后一个API请求框架等。它返回数据中的cookie值。 -
delsession =>此还接受了requestEvent的cookies方法。它可以验证cookie如果cookie不有效,它将不会删除会话,而cookie将返回错误:true,您可以在每种方法中处理无效的cookie处理操作。成功验证后,它将返回独特的值,使redis键具有前缀值。
-
deletecookie =>它还从requestEvent中采用cookie方法。此方法仅在没有任何验证的情况下从浏览器中删除cookie。例如如果您在任何方法中都有验证错误,则可以删除cookie而无需删除REDIS的会话,这只能使用有效的密钥。它返回什么都不会删除,如果有任何错误,它会登机。
其他方法可能对您自己的逻辑有用
- _validatecookie =>它从RequestEvent和验证cookie中采用cookie方法,该方法是使用RedissessionStore创建的createNewsession方法。如果没有错误,则返回没有前缀的redis键。
在我们的项目身份验证中使用方法。
在这里,我将展示如何在API(+Server.ts)中使用它们,并且可以在Sveltekit页面操作中使用。我正在做一些假设,例如您已经创建了用户并拥有
password
字段,您将处理客户提供的数据验证。
这是我们的SessionManager文件的代码
import { RedisSessionStore } from '@ethercorps/sveltekit-redis-session';
import Redis from 'ioredis';
import { SECRET, REDIS_URL } from '$env/static/private';
export const sessionManger = new RedisSessionStore({
redisClient: new Redis(REDIS_URL),
secret: SECRET,
prefix: 'redisk-example:', // redis key prefix
cookieName: 'session', // cookie name in browser
cookiesOptions: {
maxAge: 10 * 60 // ten minutes
}
});
- 第一个示例显示了如何使用createNewsession登录
login/+server.ts
中的用户
// Github: examples/src/routes/api/login/+server.ts
import { fail, json, redirect } from "@sveltejs/kit";
import type { RequestHandler } from './$types';
import { sessionManger } from '$lib/session';
export const POST = (async ({ request, locals, cookies }) => {
const { email, password } = await request.json();
if (
email !== 'shivam@example.com' ||
password !== 'Shivam@Meena'
) {
return fail(400, {
data: { email, password },
message: 'Invalid credentials'
});
} // user validation
/* get user data after validation */
const { data, error, message } = await sessionManger.createNewSession(cookies, {
email
}); // creating new session
if (error) {
console.log(message);
return fail(400, {
data: { email, password },
message
});
} // error check while creating session
return json({ success: true, message}); // no error return
}) satisfies RequestHandler;
在上面的示例中,您可以看到我们刚刚通过requestEvent和用户sessiondata将cookie传递给了REDIS创建并添加cookie并添加cookie。
- 此示例显示了如何在
+hooks.server.ts
中使用Getession
// Github: examples/src/+hooks.server.ts
import type { Handle } from '@sveltejs/kit';
import { sessionManger } from '$lib/session';
import { redirect } from '@sveltejs/kit';
export const handle: Handle = async ({ event, resolve }) => {
const userSession = await sessionManger.getSession(await event.cookies);
event.locals = {
isUserLoggedIn: false,
user: null
};
if (userSession.error) {
console.log(userSession);
await sessionManger.deleteCookie(await event.cookies);
return resolve(event);
}
if (userSession && userSession.data) {
event.locals = {
isUserLoggedIn: true,
user: { email: userSession?.data?.email as string }
};
}
return resolve(event);
};
在
hooks.server.ts
中,我们将与我们的cookie进行会话,并且它将返回sessiondata inseressessessessessesseess.data和错误,我将删除cookie。
- 此示例显示了如何在
+logout/server.ts
中使用Delsession方法
// Github: examples/src/routes/api/logout/+server.ts
import { json, redirect } from '@sveltejs/kit';
import type { RequestHandler } from './$types';
import { sessionManger } from '$lib/session';
export const POST = (async ({ request, locals, cookies }) => {
if (locals && locals.isUserLoggedIn) {
const { email } = await request.json();
const deleteData = await sessionManger.delSession(cookies);
if (deleteData.error) await sessionManger.deleteCookie(cookies);
return json({ loggedIn: false, message: 'Successfully logged out' });
}
throw redirect(302, '/');
}) satisfies RequestHandler;
在这里,我们刚刚通过了我们的cookie并检查了错误,如果发现错误已删除了应用于请求的cookie。
在上面的示例中,您已经看到了我们如何利用createNewSession
,getSession
,delSession
和deleteCookie
。您可以在项目中尝试updateSessionExpiry
和_validateCookie
,并在评论中让我知道您的所作所为和逻辑,这将非常有用。
如果有人想建议并贡献,请检查该项目的官方回购。
这是我为你写的。如果您想问或建议任何建议,请发表评论并展示一些爱。