| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293 |
- import { Request, Response, NextFunction } from 'express';
- import jwt from 'jsonwebtoken';
- import { config } from '../config/index.js';
- import { AppError } from './error.js';
- import { ERROR_CODES, HTTP_STATUS } from '@media-manager/shared';
- import type { User, UserRole } from '@media-manager/shared';
- export interface JwtPayload {
- userId: number;
- username: string;
- role: UserRole;
- }
- declare global {
- namespace Express {
- interface Request {
- user?: JwtPayload;
- }
- }
- }
- /**
- * JWT 认证中间件
- */
- export function authenticate(req: Request, _res: Response, next: NextFunction): void {
- const authHeader = req.headers.authorization;
- if (!authHeader || !authHeader.startsWith('Bearer ')) {
- throw new AppError('未提供认证令牌', HTTP_STATUS.UNAUTHORIZED, ERROR_CODES.UNAUTHORIZED);
- }
- const token = authHeader.substring(7);
- try {
- const decoded = jwt.verify(token, config.jwt.secret) as JwtPayload;
- req.user = decoded;
- next();
- } catch (error) {
- if (error instanceof jwt.TokenExpiredError) {
- throw new AppError('认证令牌已过期', HTTP_STATUS.UNAUTHORIZED, ERROR_CODES.TOKEN_EXPIRED);
- }
- throw new AppError('无效的认证令牌', HTTP_STATUS.UNAUTHORIZED, ERROR_CODES.TOKEN_INVALID);
- }
- }
- /**
- * 角色授权中间件
- */
- export function authorize(...roles: UserRole[]) {
- return (req: Request, _res: Response, next: NextFunction): void => {
- if (!req.user) {
- throw new AppError('未认证', HTTP_STATUS.UNAUTHORIZED, ERROR_CODES.UNAUTHORIZED);
- }
- if (!roles.includes(req.user.role)) {
- throw new AppError('没有权限执行此操作', HTTP_STATUS.FORBIDDEN, ERROR_CODES.FORBIDDEN);
- }
- next();
- };
- }
- /**
- * 生成访问令牌
- */
- export function generateAccessToken(payload: JwtPayload): string {
- return jwt.sign(payload, config.jwt.secret, {
- expiresIn: config.jwt.accessExpiresIn,
- });
- }
- /**
- * 生成刷新令牌
- */
- export function generateRefreshToken(payload: JwtPayload): string {
- return jwt.sign(payload, config.jwt.secret, {
- expiresIn: config.jwt.refreshExpiresIn,
- });
- }
- /**
- * 验证刷新令牌
- */
- export function verifyRefreshToken(token: string): JwtPayload {
- try {
- return jwt.verify(token, config.jwt.secret) as JwtPayload;
- } catch (error) {
- if (error instanceof jwt.TokenExpiredError) {
- throw new AppError('刷新令牌已过期', HTTP_STATUS.UNAUTHORIZED, ERROR_CODES.TOKEN_EXPIRED);
- }
- throw new AppError('无效的刷新令牌', HTTP_STATUS.UNAUTHORIZED, ERROR_CODES.TOKEN_INVALID);
- }
- }
|