'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 => { 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 { 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> { 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(), }); }