import jwt from 'jsonwebtoken'; import { redis } from '../config/redis'; import { config } from '../config'; export type AuthRole = 'user' | 'admin' | 'screen'; export interface SessionData { userId: string; userName?: string; role?: AuthRole; openid?: string; } export interface AuthUser { userId: string; userName?: string; role: AuthRole; token: string; openid?: string; } const SESSION_TOKEN_PREFIX = 'session:'; export function extractBearerToken(raw?: string | string[]): string | null { if (!raw) return null; const value = Array.isArray(raw) ? raw[0] : raw; const parts = value.split(' '); if (parts.length === 2 && /^Bearer$/i.test(parts[0])) { return parts[1]; } return null; } export async function createSessionToken( data: SessionData, ttlSeconds: number ): Promise { const payload = { userId: data.userId, userName: data.userName, role: data.role || 'user', openid: data.openid, }; const token = jwt.sign(payload, config.jwtSecret, { expiresIn: ttlSeconds, }); await redis.setex( `${SESSION_TOKEN_PREFIX}${token}`, ttlSeconds, JSON.stringify({ userId: data.userId, userName: data.userName, role: data.role || 'user', openid: data.openid, }) ); return token; } export async function verifySessionToken(token: string): Promise { try { const payload = jwt.verify(token, config.jwtSecret) as SessionData & { role?: AuthRole }; const data = await redis.get(`${SESSION_TOKEN_PREFIX}${token}`); if (!data) return null; const session = JSON.parse(data) as SessionData; const role = (payload.role || session.role || 'user') as AuthRole; return { userId: payload.userId || session.userId, userName: payload.userName || session.userName, role, token, openid: payload.openid || session.openid, }; } catch { return null; } }