feat: 更新 N5Proxy 以支持生成带有刷新令牌的 JWKS 令牌
This commit is contained in:
@@ -61,6 +61,8 @@ type StoreSetOpts = {
|
|||||||
loginType?: 'default' | 'plugin' | 'month' | 'season' | 'year' | 'week' | 'day'; // 登陆类型 'default' | 'plugin' | 'month' | 'season' | 'year'
|
loginType?: 'default' | 'plugin' | 'month' | 'season' | 'year' | 'week' | 'day'; // 登陆类型 'default' | 'plugin' | 'month' | 'season' | 'year'
|
||||||
expire?: number; // 过期时间,单位为秒
|
expire?: number; // 过期时间,单位为秒
|
||||||
hasRefreshToken?: boolean;
|
hasRefreshToken?: boolean;
|
||||||
|
// refreshToken的过期时间比accessToken多多少天,默认是1天
|
||||||
|
expireDay?: number;
|
||||||
[key: string]: any;
|
[key: string]: any;
|
||||||
};
|
};
|
||||||
interface Store<T> {
|
interface Store<T> {
|
||||||
@@ -70,7 +72,7 @@ interface Store<T> {
|
|||||||
expire: (key: string, ttl?: number) => Promise<void>;
|
expire: (key: string, ttl?: number) => Promise<void>;
|
||||||
delObject: (value?: T) => Promise<void>;
|
delObject: (value?: T) => Promise<void>;
|
||||||
keys: (key?: string) => Promise<string[]>;
|
keys: (key?: string) => Promise<string[]>;
|
||||||
setToken: (value: { accessToken: string; refreshToken: string; value?: T }, opts?: StoreSetOpts) => Promise<TokenData>;
|
setToken: (value: { accessToken: string; refreshToken: string; value?: T, day?: number }, opts?: StoreSetOpts) => Promise<TokenData>;
|
||||||
delKeys: (keys: string[]) => Promise<number>;
|
delKeys: (keys: string[]) => Promise<number>;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -138,9 +140,11 @@ export class RedisTokenStore implements Store<OauthUser> {
|
|||||||
await this.del(userPrefix + ':token:' + accessToken);
|
await this.del(userPrefix + ':token:' + accessToken);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
async setToken(data: { accessToken: string; refreshToken: string; value?: OauthUser }, opts?: StoreSetOpts): Promise<TokenData> {
|
async setToken(data: { accessToken: string; refreshToken: string; value?: OauthUser, day?: number }, opts?: StoreSetOpts): Promise<TokenData> {
|
||||||
const { accessToken, refreshToken, value } = data;
|
const { accessToken, refreshToken, value } = data;
|
||||||
let userPrefix = 'user:' + value?.id;
|
let userPrefix = 'user:' + value?.id;
|
||||||
|
const expireDay = data?.day || 1;
|
||||||
|
|
||||||
if (value?.orgId) {
|
if (value?.orgId) {
|
||||||
userPrefix = 'org:' + value?.orgId + ':user:' + value?.id;
|
userPrefix = 'org:' + value?.orgId + ':user:' + value?.id;
|
||||||
}
|
}
|
||||||
@@ -171,13 +175,9 @@ export class RedisTokenStore implements Store<OauthUser> {
|
|||||||
|
|
||||||
await this.set(accessToken, JSON.stringify(value), expire);
|
await this.set(accessToken, JSON.stringify(value), expire);
|
||||||
await this.set(userPrefix + ':token:' + accessToken, accessToken, expire);
|
await this.set(userPrefix + ':token:' + accessToken, accessToken, expire);
|
||||||
// refreshToken的过期时间比accessToken多2天,确保在accessToken过期后,refreshToken仍然有效
|
// refreshToken的过期时间比accessToken多expireDay天,确保在accessToken过期后,refreshToken仍然有效
|
||||||
let refreshTokenExpiresIn = expire + 2 * day;
|
let refreshTokenExpiresIn = expire + expireDay * day;
|
||||||
if (refreshToken) {
|
if (refreshToken) {
|
||||||
// 小于7天, 则设置为7天
|
|
||||||
if (refreshTokenExpiresIn < 60 * 60 * 24 * 7) {
|
|
||||||
refreshTokenExpiresIn = 60 * 60 * 24 * 7;
|
|
||||||
}
|
|
||||||
await this.set(refreshToken, JSON.stringify(value), refreshTokenExpiresIn);
|
await this.set(refreshToken, JSON.stringify(value), refreshTokenExpiresIn);
|
||||||
await this.set(userPrefix + ':refreshToken:' + refreshToken, refreshToken, refreshTokenExpiresIn);
|
await this.set(userPrefix + ':refreshToken:' + refreshToken, refreshToken, refreshTokenExpiresIn);
|
||||||
}
|
}
|
||||||
@@ -239,7 +239,7 @@ export class OAuth<T extends OauthUser> {
|
|||||||
user.oauthExpand.refreshToken = refreshToken;
|
user.oauthExpand.refreshToken = refreshToken;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const tokenData = await this.store.setToken({ accessToken, refreshToken, value: user }, expandOpts);
|
const tokenData = await this.store.setToken({ accessToken, refreshToken, value: user, day: expandOpts?.day }, expandOpts);
|
||||||
|
|
||||||
return tokenData;
|
return tokenData;
|
||||||
}
|
}
|
||||||
@@ -253,7 +253,7 @@ export class OAuth<T extends OauthUser> {
|
|||||||
createTime: new Date().getTime(), // 创建时间
|
createTime: new Date().getTime(), // 创建时间
|
||||||
};
|
};
|
||||||
await this.store.setToken(
|
await this.store.setToken(
|
||||||
{ accessToken: secretKey, refreshToken: '', value: oauthUser },
|
{ accessToken: secretKey, refreshToken: '', value: oauthUser, day: opts?.day },
|
||||||
{
|
{
|
||||||
...opts,
|
...opts,
|
||||||
hasRefreshToken: false,
|
hasRefreshToken: false,
|
||||||
@@ -338,6 +338,7 @@ export class OAuth<T extends OauthUser> {
|
|||||||
{
|
{
|
||||||
...user.oauthExpand,
|
...user.oauthExpand,
|
||||||
hasRefreshToken: true,
|
hasRefreshToken: true,
|
||||||
|
day: user.oauthExpand?.day,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
console.log('resetToken token', await this.store.keys());
|
console.log('resetToken token', await this.store.keys());
|
||||||
@@ -370,6 +371,7 @@ export class OAuth<T extends OauthUser> {
|
|||||||
{
|
{
|
||||||
...user.oauthExpand,
|
...user.oauthExpand,
|
||||||
hasRefreshToken: true,
|
hasRefreshToken: true,
|
||||||
|
day: user.oauthExpand?.day,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -429,8 +431,8 @@ export class OAuth<T extends OauthUser> {
|
|||||||
async setJwksToken(token: string, opts: { id: string; expire: number }) {
|
async setJwksToken(token: string, opts: { id: string; expire: number }) {
|
||||||
const expire = opts.expire ?? 2 * 3600; // 2 hours
|
const expire = opts.expire ?? 2 * 3600; // 2 hours
|
||||||
const id = opts.id || '-';
|
const id = opts.id || '-';
|
||||||
// jwks token的过期时间比accessToken多3天,确保3天内可以用来refresh token
|
// jwks token的过期时间比accessToken多2天,确保2天内可以用来refresh token
|
||||||
const addExpire = 3 * 24 * 3600;
|
const addExpire = 2 * 24 * 3600;
|
||||||
await this.store.redis.set('user:jwks:' + token, id, 'EX', expire + addExpire);
|
await this.store.redis.set('user:jwks:' + token, id, 'EX', expire + addExpire);
|
||||||
}
|
}
|
||||||
async deleteJwksToken(token: string) {
|
async deleteJwksToken(token: string) {
|
||||||
|
|||||||
@@ -48,7 +48,7 @@ export const N5Proxy = async (req: IncomingMessage, res: ServerResponse, opts?:
|
|||||||
}
|
}
|
||||||
try {
|
try {
|
||||||
const user = await User.findByPk(userId);
|
const user = await User.findByPk(userId);
|
||||||
const token = await User.createJwksTokenResponse({ id: userId, username: user?.username || '' }, { hasRefreshToken: false });
|
const token = await User.createJwksTokenResponse({ id: userId, username: user?.username || '' }, { hasRefreshToken: true });
|
||||||
const urlObj = new URL(link);
|
const urlObj = new URL(link);
|
||||||
urlObj.searchParams.set('token', token.accessToken);
|
urlObj.searchParams.set('token', token.accessToken);
|
||||||
const resultLink = await fetch(urlObj.toString(), { method: 'GET' }).then(res => res.json())
|
const resultLink = await fetch(urlObj.toString(), { method: 'GET' }).then(res => res.json())
|
||||||
|
|||||||
Reference in New Issue
Block a user