duoqi-api/src/middleware/admin-auth.ts
Wang Zhuoxuan c70748dde2
All checks were successful
CI/CD Pipeline / Code Quality (push) Successful in 18s
CI/CD Pipeline / Unit Tests (push) Successful in 45s
CI/CD Pipeline / Build & Deploy Test (push) Has been skipped
CI/CD Pipeline / Build & Deploy Production (push) Successful in 12m21s
fix: 修复 admin change-password 接口 401 和 CORS 问题
- CORS 配置显式放行 PUT/PATCH/DELETE 方法(默认只有 GET/POST/HEAD)
- admin-auth 白名单路径修正 /v1/admin/auth/login → /v1/admin/login
- JWT verify 后手动赋值 request.user,修复 decoded payload 丢失
2026-04-23 22:27:23 +08:00

60 lines
1.6 KiB
TypeScript

import { FastifyInstance } from 'fastify';
import fp from 'fastify-plugin';
import { UnauthorizedError, ForbiddenError } from '../utils/errors.js';
import { config } from '../utils/config.js';
import type { JwtPayload } from '../types/auth.js';
// Extend @fastify/jwt's type system for admin JWT
declare module '@fastify/jwt' {
interface FastifyJWT {
payload: JwtPayload;
}
}
async function adminAuthMiddleware(app: FastifyInstance): Promise<void> {
app.addHook('onRequest', async (request) => {
if (!request.url.startsWith('/v1/admin')) {
return;
}
// Skip public admin endpoints
const publicPaths = ['/v1/admin/auth', '/v1/admin/login'];
if (publicPaths.some((p) => request.url === p)) {
return;
}
const authHeader = request.headers.authorization;
if (!authHeader?.startsWith('Bearer ')) {
throw new UnauthorizedError('Missing admin token');
}
const token = authHeader.slice(7);
// Try JWT verification first (new way)
try {
const decoded = app.jwt.verify<JwtPayload>(token);
if (decoded.authType === 'admin') {
request.user = decoded;
return;
}
} catch {
// JWT verification failed, try fallback (backward compatibility)
}
// Fallback: ADMIN_TOKEN (legacy way)
if (token === config.ADMIN_TOKEN) {
// Manually attach a fake decoded payload for legacy token
request.jwtVerify = async () => ({
userId: 'legacy-admin',
authType: 'admin',
role: 'super_admin',
});
return;
}
throw new ForbiddenError('Invalid admin token');
});
}
export default fp(adminAuthMiddleware);