auth.ts 7.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240
  1. import { Request, Response, NextFunction } from 'express';
  2. import jwt from 'jsonwebtoken';
  3. import { AppError } from './errorHandler';
  4. import { LoggerService } from '../services/loggerService';
  5. // 扩展Request接口,添加user属性
  6. declare global {
  7. namespace Express {
  8. interface Request {
  9. user?: { id: string; username: string; role?: string };
  10. }
  11. }
  12. }
  13. /**
  14. * 认证中间件
  15. * 验证请求头中的Authorization令牌
  16. */
  17. export const authenticateToken = (req: Request, res: Response, next: NextFunction): void => {
  18. try {
  19. // 从请求头获取令牌
  20. const authHeader = req.headers['authorization'];
  21. const token = authHeader && authHeader.split(' ')[1]; // Bearer TOKEN
  22. if (!token) {
  23. // 记录认证失败日志(缺少令牌)
  24. LoggerService.warn('认证失败:未提供认证令牌', {
  25. source: 'auth',
  26. module: 'authenticate_token',
  27. details: JSON.stringify({
  28. path: req.path,
  29. method: req.method,
  30. ip: req.ip,
  31. userAgent: req.get('user-agent')
  32. })
  33. }).catch(err => {
  34. console.error('认证失败日志写入失败:', err);
  35. });
  36. throw new AppError('未提供认证令牌', 401);
  37. }
  38. // 检查是否为模拟token(以mock_token_开头)
  39. if (token.startsWith('mock_token_')) {
  40. // 解析模拟token
  41. const parts = token.split('_');
  42. if (parts.length < 3) {
  43. // 记录认证失败日志(无效的模拟令牌)
  44. LoggerService.warn('认证失败:无效的认证令牌', {
  45. source: 'auth',
  46. module: 'authenticate_token',
  47. details: JSON.stringify({
  48. tokenType: 'mock',
  49. path: req.path,
  50. method: req.method,
  51. ip: req.ip
  52. })
  53. }).catch(err => {
  54. console.error('认证失败日志写入失败:', err);
  55. });
  56. throw new AppError('无效的认证令牌', 401);
  57. }
  58. const userId = parts[2];
  59. // 从数据库获取用户信息
  60. const UserModel = require('../models/user').UserModel;
  61. UserModel.getById(userId).then((user: any) => {
  62. if (!user) {
  63. // 记录认证失败日志(用户不存在)
  64. LoggerService.warn('认证失败:用户不存在', {
  65. source: 'auth',
  66. module: 'authenticate_token',
  67. details: JSON.stringify({
  68. userId,
  69. tokenType: 'mock',
  70. path: req.path,
  71. method: req.method,
  72. ip: req.ip
  73. })
  74. }).catch(err => {
  75. console.error('认证失败日志写入失败:', err);
  76. });
  77. throw new AppError('用户不存在', 401);
  78. }
  79. // 将用户信息添加到请求对象
  80. req.user = {
  81. id: user.id,
  82. username: user.username,
  83. role: user.role
  84. };
  85. // 记录认证成功日志
  86. LoggerService.info('认证成功', {
  87. source: 'auth',
  88. module: 'authenticate_token',
  89. details: JSON.stringify({
  90. userId: user.id,
  91. username: user.username,
  92. role: user.role,
  93. tokenType: 'mock',
  94. path: req.path,
  95. method: req.method,
  96. ip: req.ip
  97. })
  98. }).catch(err => {
  99. console.error('认证成功日志写入失败:', err);
  100. });
  101. next();
  102. }).catch((error: any) => {
  103. next(error);
  104. });
  105. } else {
  106. // 验证JWT令牌
  107. const decoded = jwt.verify(token, process.env.JWT_SECRET as string) as {
  108. id: string;
  109. username: string;
  110. role?: string;
  111. };
  112. // 将解码后的用户信息添加到请求对象
  113. req.user = decoded;
  114. // 记录认证成功日志
  115. LoggerService.info('认证成功', {
  116. source: 'auth',
  117. module: 'authenticate_token',
  118. details: JSON.stringify({
  119. userId: decoded.id,
  120. username: decoded.username,
  121. role: decoded.role,
  122. tokenType: 'jwt',
  123. path: req.path,
  124. method: req.method,
  125. ip: req.ip
  126. })
  127. }).catch(err => {
  128. console.error('认证成功日志写入失败:', err);
  129. });
  130. next();
  131. }
  132. } catch (error) {
  133. if (error instanceof jwt.JsonWebTokenError) {
  134. LoggerService.warn('认证失败:无效的认证令牌', {
  135. source: 'auth',
  136. module: 'authenticate_token',
  137. details: JSON.stringify({
  138. tokenType: 'jwt',
  139. error: (error as jwt.JsonWebTokenError).message,
  140. path: req.path,
  141. method: req.method,
  142. ip: req.ip
  143. })
  144. }).catch((err: unknown) => {
  145. console.error('认证失败日志写入失败:', err);
  146. });
  147. next(new AppError('无效的认证令牌', 401));
  148. } else if (error instanceof jwt.TokenExpiredError) {
  149. LoggerService.warn('认证失败:认证令牌已过期', {
  150. source: 'auth',
  151. module: 'authenticate_token',
  152. details: JSON.stringify({
  153. tokenType: 'jwt',
  154. expiredAt: (error as jwt.TokenExpiredError).expiredAt,
  155. path: req.path,
  156. method: req.method,
  157. ip: req.ip
  158. })
  159. }).catch((err: unknown) => {
  160. console.error('认证失败日志写入失败:', err);
  161. });
  162. next(new AppError('认证令牌已过期', 401));
  163. } else if (error instanceof Error) {
  164. next(error);
  165. } else {
  166. next(new AppError('认证失败', 401));
  167. }
  168. }
  169. };
  170. /**
  171. * 角色授权中间件
  172. * 检查用户是否具有指定角色
  173. */
  174. export const authorizeRole = (roles: string[]) => {
  175. return (req: Request, res: Response, next: NextFunction): void => {
  176. if (!req.user || !req.user.role || !roles.includes(req.user.role)) {
  177. // 记录授权失败日志
  178. LoggerService.warn('授权失败:没有权限执行此操作', {
  179. source: 'auth',
  180. module: 'authorize_role',
  181. details: JSON.stringify({
  182. userRole: req.user?.role,
  183. requiredRoles: roles,
  184. path: req.path,
  185. method: req.method,
  186. userId: req.user?.id,
  187. username: req.user?.username,
  188. ip: req.ip
  189. })
  190. }).catch(err => {
  191. console.error('授权失败日志写入失败:', err);
  192. });
  193. throw new AppError('没有权限执行此操作', 403);
  194. }
  195. // 记录授权成功日志
  196. LoggerService.info('授权成功', {
  197. source: 'auth',
  198. module: 'authorize_role',
  199. details: JSON.stringify({
  200. userRole: req.user.role,
  201. requiredRoles: roles,
  202. path: req.path,
  203. method: req.method,
  204. userId: req.user.id,
  205. username: req.user.username,
  206. ip: req.ip
  207. })
  208. }).catch(err => {
  209. console.error('授权成功日志写入失败:', err);
  210. });
  211. next();
  212. };
  213. };
  214. /**
  215. * 管理员权限中间件
  216. * 检查用户是否具有admin角色
  217. */
  218. export const requireAdmin = authorizeRole(['admin']);