优化 token 处理逻辑,统一 createCookie 调用格式,返回 token 过期时间

This commit is contained in:
2026-02-02 17:02:20 +08:00
parent a0f0f65d20
commit 82e3392b36
5 changed files with 55 additions and 27 deletions

View File

@@ -62,7 +62,13 @@ export class User extends Model {
oauthUser.orgId = id; oauthUser.orgId = id;
} }
const token = await oauth.generateToken(oauthUser, { type: loginType, hasRefreshToken: true, ...expand }); const token = await oauth.generateToken(oauthUser, { type: loginType, hasRefreshToken: true, ...expand });
return { accessToken: token.accessToken, refreshToken: token.refreshToken, token: token.accessToken }; return {
accessToken: token.accessToken,
refreshToken: token.refreshToken,
token: token.accessToken,
accessTokenExpiresAt: token.accessTokenExpiresAt,
refreshTokenExpiresAt: token.refreshTokenExpiresAt,
};
} }
/** /**
* 验证token * 验证token

View File

@@ -70,9 +70,16 @@ 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<void>; setToken: (value: { accessToken: string; refreshToken: string; value?: T }, opts?: StoreSetOpts) => Promise<TokenData>;
delKeys: (keys: string[]) => Promise<number>; delKeys: (keys: string[]) => Promise<number>;
} }
type TokenData = {
accessToken: string;
accessTokenExpiresAt: number;
refreshToken?: string;
refreshTokenExpiresAt?: number;
}
export class RedisTokenStore implements Store<OauthUser> { export class RedisTokenStore implements Store<OauthUser> {
redis: Redis; redis: Redis;
private prefix: string = 'oauth:'; private prefix: string = 'oauth:';
@@ -131,7 +138,7 @@ 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) { async setToken(data: { accessToken: string; refreshToken: string; value?: OauthUser }, opts?: StoreSetOpts): Promise<TokenData> {
const { accessToken, refreshToken, value } = data; const { accessToken, refreshToken, value } = data;
let userPrefix = 'user:' + value?.id; let userPrefix = 'user:' + value?.id;
if (value?.orgId) { if (value?.orgId) {
@@ -163,14 +170,20 @@ 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);
let refreshTokenExpiresAt = Math.min(expire * 7, 60 * 60 * 24 * 30, 60 * 60 * 24 * 365); // 最大为一年
if (refreshToken) { if (refreshToken) {
let refreshTokenExpire = Math.min(expire * 7, 60 * 60 * 24 * 30, 60 * 60 * 24 * 365); // 最大为一年
// 小于7天, 则设置为7天 // 小于7天, 则设置为7天
if (refreshTokenExpire < 60 * 60 * 24 * 7) { if (refreshTokenExpiresAt < 60 * 60 * 24 * 7) {
refreshTokenExpire = 60 * 60 * 24 * 7; refreshTokenExpiresAt = 60 * 60 * 24 * 7;
} }
await this.set(refreshToken, JSON.stringify(value), refreshTokenExpire); await this.set(refreshToken, JSON.stringify(value), refreshTokenExpiresAt);
await this.set(userPrefix + ':refreshToken:' + refreshToken, refreshToken, refreshTokenExpire); await this.set(userPrefix + ':refreshToken:' + refreshToken, refreshToken, refreshTokenExpiresAt);
}
return {
accessToken,
accessTokenExpiresAt: expire,
refreshToken,
refreshTokenExpiresAt,
} }
} }
async delKeys(keys: string[]) { async delKeys(keys: string[]) {
@@ -206,10 +219,7 @@ export class OAuth<T extends OauthUser> {
async generateToken( async generateToken(
user: T, user: T,
expandOpts?: StoreSetOpts, expandOpts?: StoreSetOpts,
): Promise<{ ): Promise<TokenData> {
accessToken: string;
refreshToken?: string;
}> {
// 拥有refreshToken 为 true 时accessToken 为 st_ 开头refreshToken 为 rk_开头 // 拥有refreshToken 为 true 时accessToken 为 st_ 开头refreshToken 为 rk_开头
// 意思是secretToken 和 secretKey的缩写 // 意思是secretToken 和 secretKey的缩写
const accessToken = expandOpts?.hasRefreshToken ? 'st_' + randomId32() : 'sk_' + randomId64(); const accessToken = expandOpts?.hasRefreshToken ? 'st_' + randomId32() : 'sk_' + randomId64();
@@ -227,9 +237,9 @@ export class OAuth<T extends OauthUser> {
user.oauthExpand.refreshToken = refreshToken; user.oauthExpand.refreshToken = refreshToken;
} }
} }
await this.store.setToken({ accessToken, refreshToken, value: user }, expandOpts); const tokenData = await this.store.setToken({ accessToken, refreshToken, value: user }, expandOpts);
return { accessToken, refreshToken }; return tokenData;
} }
async saveSecretKey(oauthUser: T, secretKey: string, opts?: StoreSetOpts) { async saveSecretKey(oauthUser: T, secretKey: string, opts?: StoreSetOpts) {
// 生成一个secretKey // 生成一个secretKey

View File

@@ -59,10 +59,7 @@ app
} }
} }
await config.update({ await config.update({
data: { data: data,
...config.data,
...data,
},
...rest, ...rest,
}); });
if (config.data?.permission?.share === 'public') { if (config.data?.permission?.share === 'public') {
@@ -80,7 +77,7 @@ app
}); });
if (config) { if (config) {
await config.update({ await config.update({
data: { ...config.data, ...data }, data: data,
...rest, ...rest,
}); });
ctx.body = config; ctx.body = config;
@@ -177,7 +174,7 @@ app
const search: any = id ? { id } : { key }; const search: any = id ? { id } : { key };
const config = await ConfigModel.findOne({ const config = await ConfigModel.findOne({
where: { where: {
...search ...search
}, },
}); });
if (config && config.uid === tuid) { if (config && config.uid === tuid) {

View File

@@ -153,7 +153,9 @@ app
browser: someInfo['user-agent'], browser: someInfo['user-agent'],
host: someInfo.host, host: someInfo.host,
}); });
createCookie(token, ctx); createCookie({
token: token.accessToken
}, ctx);
ctx.body = token; ctx.body = token;
}) })
.addTo(app); .addTo(app);
@@ -259,7 +261,10 @@ app
const refreshToken = accessUser.oauthExpand?.refreshToken; const refreshToken = accessUser.oauthExpand?.refreshToken;
if (refreshToken) { if (refreshToken) {
const result = await User.oauth.refreshToken(refreshToken); const result = await User.oauth.refreshToken(refreshToken);
createCookie(result, ctx); createCookie({
token: result.accessToken
}, ctx);
ctx.body = result; ctx.body = result;
return; return;
} else if (accessUser) { } else if (accessUser) {
@@ -268,7 +273,9 @@ app
...accessUser.oauthExpand, ...accessUser.oauthExpand,
hasRefreshToken: true, hasRefreshToken: true,
}); });
createCookie(result, ctx); createCookie({
token: result.accessToken
}, ctx);
ctx.body = result; ctx.body = result;
return; return;
} }
@@ -323,13 +330,17 @@ app
if (orgsList.includes(username)) { if (orgsList.includes(username)) {
if (tokenUsername === username) { if (tokenUsername === username) {
const result = await User.oauth.resetToken(token); const result = await User.oauth.resetToken(token);
createCookie(result, ctx); createCookie({
token: result.accessToken,
}, ctx);
await User.oauth.delToken(token); await User.oauth.delToken(token);
ctx.body = result; ctx.body = result;
} else { } else {
const user = await User.findOne({ where: { username } }); const user = await User.findOne({ where: { username } });
const result = await user.createToken(userId, 'default'); const result = await user.createToken(userId, 'default');
createCookie(result, ctx); createCookie({
token: result.accessToken,
}, ctx);
ctx.body = result; ctx.body = result;
} }
} else { } else {
@@ -352,7 +363,9 @@ app
const result = await User.oauth.refreshToken(refreshToken); const result = await User.oauth.refreshToken(refreshToken);
if (result) { if (result) {
console.log('refreshToken result', result); console.log('refreshToken result', result);
createCookie(result, ctx); createCookie({
token: result.accessToken,
}, ctx);
ctx.body = result; ctx.body = result;
} else { } else {
ctx.throw(500, 'Refresh Token Failed, please login again'); ctx.throw(500, 'Refresh Token Failed, please login again');

View File

@@ -109,7 +109,9 @@ app
const token = JSON.parse(data); const token = JSON.parse(data);
if (token.accessToken) { if (token.accessToken) {
ctx.body = token; ctx.body = token;
createCookie(token, ctx); createCookie({
token: token.accessToken,
}, ctx);
} else { } else {
ctx.throw(500, 'Checked error Failed, login failed, please login again'); ctx.throw(500, 'Checked error Failed, login failed, please login again');
} }