feat: 添加JWKS管理功能,支持基于用户token创建新token
This commit is contained in:
@@ -1,7 +1,7 @@
|
||||
import { useContextKey } from '@kevisual/context';
|
||||
import { Redis } from 'ioredis';
|
||||
import { User } from './user.ts';
|
||||
import { oauth } from '../oauth/auth.ts';
|
||||
import { oauth, jwksManager } from '../oauth/auth.ts';
|
||||
import { OauthUser } from '../oauth/oauth.ts';
|
||||
import { db } from '../../modules/db.ts';
|
||||
import { cfUserSecrets, cfUser } from '../../db/drizzle/schema.ts';
|
||||
@@ -53,6 +53,10 @@ export class UserSecret {
|
||||
* @returns
|
||||
*/
|
||||
static async verifyToken(token: string) {
|
||||
if (token?.includes?.('.')) {
|
||||
// 先尝试作为jwt token验证,如果验证成功则直接返回用户信息
|
||||
return await jwksManager.verify(token);
|
||||
}
|
||||
if (!oauth.isSecretKey(token)) {
|
||||
return await oauth.verifyToken(token);
|
||||
}
|
||||
@@ -62,11 +66,11 @@ export class UserSecret {
|
||||
}
|
||||
console.log('verifyToken: try to verify as secret key');
|
||||
const userSecrets = await db.select().from(userSecretsTable).where(eq(userSecretsTable.token, token)).limit(1);
|
||||
|
||||
|
||||
if (userSecrets.length === 0) {
|
||||
return null; // 如果没有找到对应的用户密钥,则返回null
|
||||
}
|
||||
|
||||
|
||||
const userSecret = new UserSecret(userSecrets[0]);
|
||||
if (userSecret.isExpired()) {
|
||||
return null; // 如果用户密钥已过期,则返回null
|
||||
@@ -97,13 +101,13 @@ export class UserSecret {
|
||||
*/
|
||||
static async findOne(where: { token?: string; id?: string }): Promise<UserSecret | null> {
|
||||
let query = db.select().from(userSecretsTable);
|
||||
|
||||
|
||||
if (where.token) {
|
||||
query = query.where(eq(userSecretsTable.token, where.token)) as any;
|
||||
} else if (where.id) {
|
||||
query = query.where(eq(userSecretsTable.id, where.id)) as any;
|
||||
}
|
||||
|
||||
|
||||
const secrets = await query.limit(1);
|
||||
return secrets.length > 0 ? new UserSecret(secrets[0]) : null;
|
||||
}
|
||||
@@ -119,12 +123,12 @@ export class UserSecret {
|
||||
owner: usersTable.owner,
|
||||
data: usersTable.data,
|
||||
}).from(usersTable).where(eq(usersTable.id, this.userId)).limit(1);
|
||||
|
||||
|
||||
let org: any = null;
|
||||
if (users.length === 0) {
|
||||
return null; // 如果没有找到对应的用户,则返回null
|
||||
}
|
||||
|
||||
|
||||
const user = users[0];
|
||||
const expiredTime = this.expiredTime ? new Date(this.expiredTime).getTime() : null;
|
||||
const oauthUser: Partial<OauthUser> = {
|
||||
@@ -142,7 +146,7 @@ export class UserSecret {
|
||||
type: usersTable.type,
|
||||
owner: usersTable.owner,
|
||||
}).from(usersTable).where(eq(usersTable.id, this.orgId)).limit(1);
|
||||
|
||||
|
||||
if (orgUsers.length > 0) {
|
||||
org = orgUsers[0];
|
||||
oauthUser.id = org.id;
|
||||
@@ -164,7 +168,7 @@ export class UserSecret {
|
||||
const expiredTime = new Date(this.expiredTime);
|
||||
return now > expiredTime.getTime(); // 如果当前时间大于过期时间,则认为已过期
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 检查是否过期,如果过期则更新状态为expired
|
||||
*
|
||||
@@ -225,7 +229,7 @@ export class UserSecret {
|
||||
await this.save();
|
||||
return token;
|
||||
}
|
||||
|
||||
|
||||
static async createToken() {
|
||||
let token = oauth.generateSecretKey();
|
||||
// 确保生成的token是唯一的
|
||||
@@ -234,7 +238,7 @@ export class UserSecret {
|
||||
}
|
||||
return token;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 根据 unionid 生成redis的key
|
||||
* `wxmp:unionid:token:${unionid}`
|
||||
@@ -244,13 +248,13 @@ export class UserSecret {
|
||||
static wxRedisKey(unionid: string) {
|
||||
return `wxmp:unionid:token:${unionid}`;
|
||||
}
|
||||
|
||||
|
||||
static getExpiredTime(expireDays?: number) {
|
||||
const defaultExpireDays = expireDays || 365;
|
||||
const expireTime = defaultExpireDays * 24 * 60 * 60 * 1000;
|
||||
return new Date(Date.now() + expireTime);
|
||||
}
|
||||
|
||||
|
||||
static async createSecret(tokenUser: { id: string; uid?: string, title?: string }, expireDays = 365) {
|
||||
const token = await UserSecret.createToken();
|
||||
let userId = tokenUser.id;
|
||||
@@ -259,18 +263,18 @@ export class UserSecret {
|
||||
userId = tokenUser.uid;
|
||||
orgId = tokenUser.id;
|
||||
}
|
||||
|
||||
|
||||
const insertData: Partial<typeof userSecretsTable.$inferInsert> = {
|
||||
userId,
|
||||
token,
|
||||
title: tokenUser.title || randomString(6),
|
||||
expiredTime: UserSecret.getExpiredTime(expireDays).toISOString(),
|
||||
};
|
||||
|
||||
|
||||
if (orgId !== null && orgId !== undefined) {
|
||||
insertData.orgId = orgId;
|
||||
}
|
||||
|
||||
|
||||
const inserted = await db.insert(userSecretsTable).values(insertData).returning();
|
||||
|
||||
return new UserSecret(inserted[0]);
|
||||
|
||||
Reference in New Issue
Block a user