| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240 |
- import { Request, Response, NextFunction } from 'express';
- import jwt from 'jsonwebtoken';
- import { AppError } from './errorHandler';
- import { LoggerService } from '../services/loggerService';
- // 扩展Request接口,添加user属性
- declare global {
- namespace Express {
- interface Request {
- user?: { id: string; username: string; role?: string };
- }
- }
- }
- /**
- * 认证中间件
- * 验证请求头中的Authorization令牌
- */
- export const authenticateToken = (req: Request, res: Response, next: NextFunction): void => {
- try {
- // 从请求头获取令牌
- const authHeader = req.headers['authorization'];
- const token = authHeader && authHeader.split(' ')[1]; // Bearer TOKEN
- if (!token) {
- // 记录认证失败日志(缺少令牌)
- LoggerService.warn('认证失败:未提供认证令牌', {
- source: 'auth',
- module: 'authenticate_token',
- details: JSON.stringify({
- path: req.path,
- method: req.method,
- ip: req.ip,
- userAgent: req.get('user-agent')
- })
- }).catch(err => {
- console.error('认证失败日志写入失败:', err);
- });
-
- throw new AppError('未提供认证令牌', 401);
- }
- // 检查是否为模拟token(以mock_token_开头)
- if (token.startsWith('mock_token_')) {
- // 解析模拟token
- const parts = token.split('_');
- if (parts.length < 3) {
- // 记录认证失败日志(无效的模拟令牌)
- LoggerService.warn('认证失败:无效的认证令牌', {
- source: 'auth',
- module: 'authenticate_token',
- details: JSON.stringify({
- tokenType: 'mock',
- path: req.path,
- method: req.method,
- ip: req.ip
- })
- }).catch(err => {
- console.error('认证失败日志写入失败:', err);
- });
-
- throw new AppError('无效的认证令牌', 401);
- }
-
- const userId = parts[2];
-
- // 从数据库获取用户信息
- const UserModel = require('../models/user').UserModel;
- UserModel.getById(userId).then((user: any) => {
- if (!user) {
- // 记录认证失败日志(用户不存在)
- LoggerService.warn('认证失败:用户不存在', {
- source: 'auth',
- module: 'authenticate_token',
- details: JSON.stringify({
- userId,
- tokenType: 'mock',
- path: req.path,
- method: req.method,
- ip: req.ip
- })
- }).catch(err => {
- console.error('认证失败日志写入失败:', err);
- });
-
- throw new AppError('用户不存在', 401);
- }
-
- // 将用户信息添加到请求对象
- req.user = {
- id: user.id,
- username: user.username,
- role: user.role
- };
-
- // 记录认证成功日志
- LoggerService.info('认证成功', {
- source: 'auth',
- module: 'authenticate_token',
- details: JSON.stringify({
- userId: user.id,
- username: user.username,
- role: user.role,
- tokenType: 'mock',
- path: req.path,
- method: req.method,
- ip: req.ip
- })
- }).catch(err => {
- console.error('认证成功日志写入失败:', err);
- });
-
- next();
- }).catch((error: any) => {
- next(error);
- });
- } else {
- // 验证JWT令牌
- const decoded = jwt.verify(token, process.env.JWT_SECRET as string) as {
- id: string;
- username: string;
- role?: string;
- };
- // 将解码后的用户信息添加到请求对象
- req.user = decoded;
-
- // 记录认证成功日志
- LoggerService.info('认证成功', {
- source: 'auth',
- module: 'authenticate_token',
- details: JSON.stringify({
- userId: decoded.id,
- username: decoded.username,
- role: decoded.role,
- tokenType: 'jwt',
- path: req.path,
- method: req.method,
- ip: req.ip
- })
- }).catch(err => {
- console.error('认证成功日志写入失败:', err);
- });
-
- next();
- }
- } catch (error) {
- if (error instanceof jwt.JsonWebTokenError) {
- LoggerService.warn('认证失败:无效的认证令牌', {
- source: 'auth',
- module: 'authenticate_token',
- details: JSON.stringify({
- tokenType: 'jwt',
- error: (error as jwt.JsonWebTokenError).message,
- path: req.path,
- method: req.method,
- ip: req.ip
- })
- }).catch((err: unknown) => {
- console.error('认证失败日志写入失败:', err);
- });
-
- next(new AppError('无效的认证令牌', 401));
- } else if (error instanceof jwt.TokenExpiredError) {
- LoggerService.warn('认证失败:认证令牌已过期', {
- source: 'auth',
- module: 'authenticate_token',
- details: JSON.stringify({
- tokenType: 'jwt',
- expiredAt: (error as jwt.TokenExpiredError).expiredAt,
- path: req.path,
- method: req.method,
- ip: req.ip
- })
- }).catch((err: unknown) => {
- console.error('认证失败日志写入失败:', err);
- });
-
- next(new AppError('认证令牌已过期', 401));
- } else if (error instanceof Error) {
- next(error);
- } else {
- next(new AppError('认证失败', 401));
- }
- }
- };
- /**
- * 角色授权中间件
- * 检查用户是否具有指定角色
- */
- export const authorizeRole = (roles: string[]) => {
- return (req: Request, res: Response, next: NextFunction): void => {
- if (!req.user || !req.user.role || !roles.includes(req.user.role)) {
- // 记录授权失败日志
- LoggerService.warn('授权失败:没有权限执行此操作', {
- source: 'auth',
- module: 'authorize_role',
- details: JSON.stringify({
- userRole: req.user?.role,
- requiredRoles: roles,
- path: req.path,
- method: req.method,
- userId: req.user?.id,
- username: req.user?.username,
- ip: req.ip
- })
- }).catch(err => {
- console.error('授权失败日志写入失败:', err);
- });
-
- throw new AppError('没有权限执行此操作', 403);
- }
-
- // 记录授权成功日志
- LoggerService.info('授权成功', {
- source: 'auth',
- module: 'authorize_role',
- details: JSON.stringify({
- userRole: req.user.role,
- requiredRoles: roles,
- path: req.path,
- method: req.method,
- userId: req.user.id,
- username: req.user.username,
- ip: req.ip
- })
- }).catch(err => {
- console.error('授权成功日志写入失败:', err);
- });
-
- next();
- };
- };
- /**
- * 管理员权限中间件
- * 检查用户是否具有admin角色
- */
- export const requireAdmin = authorizeRole(['admin']);
|