新增 /v1/admin/auth/login 接口,支持用户名密码登录获取 JWT Token。 - 添加 admin_users 表存储管理员账号和哈希密码 - 使用 bcryptjs 进行密码哈希(cost=10) - JWT Token 认证优先,保留 ADMIN_TOKEN 作为向后兼容 - 记录登录审计日志到 admin_audit_log - 种子数据创建默认管理员(username: admin, password: admin123) Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
60 lines
1.7 KiB
TypeScript
60 lines
1.7 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/auth/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') {
|
|
// Successfully verified admin JWT - request.jwtVerify() will attach the decoded payload
|
|
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);
|