init test

This commit is contained in:
2026-01-24 00:43:25 +08:00
parent 51aed643a0
commit 5657bffd39
22 changed files with 1182 additions and 18 deletions

83
convex/actions/jwt.ts Normal file
View File

@@ -0,0 +1,83 @@
'use node';
import * as jose from "jose";
import type { GenericId } from "convex/values";
// JWT 验证配置
const JWT_CONFIG = {
// jwksUri: "https://kevisual.cn/root/convex/jwks.json",
jwksUri: "http://convex.kevisual.cn:3211/root/convex/jwks.json",
issuer: "https://kevisual.cn",
audience: "test-convex-app",
algorithms: ["RS256"],
};
// 创建 JWKS 缓存
let jwksCache: jose.JWTVerifyGetKey | null = null;
function getJWKS() {
if (!jwksCache) {
jwksCache = jose.createRemoteJWKSet(new URL(JWT_CONFIG.jwksUri));
}
return jwksCache;
}
export const createJwt = async (payload: jose.JWTPayload): Promise<string> => {
const secret = new TextEncoder().encode("your-256-bit-secret");
const token = await new jose.SignJWT(payload)
.setProtectedHeader({ alg: "HS256", typ: "JWT" })
.setIssuedAt()
.setExpirationTime("2h")
.sign(secret);
return token;
}
// 验证 JWT token 并返回 payload
export async function verifyToken(token: string): Promise<jose.JWTPayload> {
const JWKS = getJWKS();
const { payload } = await jose.jwtVerify(token, JWKS, {
issuer: JWT_CONFIG.issuer,
audience: JWT_CONFIG.audience,
algorithms: JWT_CONFIG.algorithms,
});
return payload;
}
// 从请求 header 中提取 Bearer token
export function extractBearerToken(authHeader: string | null): string | null {
if (!authHeader) return null;
const match = authHeader.match(/^Bearer\s+(.+)$/i);
return match ? match[1] : null;
}
// 获取或创建用户(演示用)
export async function getOrCreateUser(
db: any,
tokenPayload: jose.JWTPayload
): Promise<GenericId<"users">> {
const externalId = tokenPayload.sub as string;
// 查找已存在的用户
const existingUser = await db
.query("users")
.withIndex("id", (q: any) => q.eq("id", externalId))
.first();
if (existingUser) {
// 更新最后登录时间
await db
.table("users")
.doc(existingUser._id)
.patch({ lastLoginAt: new Date().toISOString() });
return existingUser._id;
}
// 创建新用户
return await db
.table("users")
.insert({
id: externalId,
name: (tokenPayload.name as string) || "Unknown",
email: (tokenPayload.email as string) || "",
createdAt: new Date().toISOString(),
});
}