Files
nxxmdata/bank-backend/middleware/auth.js

226 lines
5.1 KiB
JavaScript
Raw Normal View History

2025-09-17 18:04:28 +08:00
/**
* 认证中间件
* @file auth.js
* @description 处理用户认证和授权
*/
const jwt = require('jsonwebtoken');
const { User, Role } = require('../models');
/**
* 验证JWT令牌
* @param {Object} req 请求对象
* @param {Object} res 响应对象
* @param {Function} next 下一个中间件
*/
const verifyToken = async (req, res, next) => {
try {
const token = req.header('Authorization')?.replace('Bearer ', '');
if (!token) {
return res.status(401).json({
success: false,
message: '访问被拒绝,未提供令牌'
});
}
const decoded = jwt.verify(token, process.env.JWT_SECRET);
const user = await User.findByPk(decoded.id, {
include: [{
model: Role,
as: 'role'
}]
});
if (!user) {
return res.status(401).json({
success: false,
message: '令牌无效,用户不存在'
});
}
if (user.status !== 'active') {
return res.status(401).json({
success: false,
message: '账户已被禁用'
});
}
req.user = user;
next();
} catch (error) {
if (error.name === 'TokenExpiredError') {
return res.status(401).json({
success: false,
message: '令牌已过期'
});
} else if (error.name === 'JsonWebTokenError') {
return res.status(401).json({
success: false,
message: '令牌无效'
});
} else {
console.error('认证中间件错误:', error);
return res.status(500).json({
success: false,
message: '服务器内部错误'
});
}
}
};
/**
* 检查用户角色权限
* @param {String|Array} roles 允许的角色
* @returns {Function} 中间件函数
*/
const requireRole = (roles) => {
return async (req, res, next) => {
try {
if (!req.user) {
return res.status(401).json({
success: false,
message: '请先登录'
});
}
const userRole = req.user.role;
if (!userRole) {
return res.status(403).json({
success: false,
message: '用户角色未分配'
});
}
const allowedRoles = Array.isArray(roles) ? roles : [roles];
if (!allowedRoles.includes(userRole.name)) {
return res.status(403).json({
success: false,
message: '权限不足'
});
}
next();
} catch (error) {
console.error('角色权限检查错误:', error);
return res.status(500).json({
success: false,
message: '服务器内部错误'
});
}
};
};
/**
* 检查用户权限级别
* @param {Number} minLevel 最小权限级别
* @returns {Function} 中间件函数
*/
const requireLevel = (minLevel) => {
return async (req, res, next) => {
try {
if (!req.user) {
return res.status(401).json({
success: false,
message: '请先登录'
});
}
const userRole = req.user.role;
if (!userRole || userRole.level < minLevel) {
return res.status(403).json({
success: false,
message: '权限级别不足'
});
}
next();
} catch (error) {
console.error('权限级别检查错误:', error);
return res.status(500).json({
success: false,
message: '服务器内部错误'
});
}
};
};
/**
* 可选认证中间件不强制要求登录
* @param {Object} req 请求对象
* @param {Object} res 响应对象
* @param {Function} next 下一个中间件
*/
const optionalAuth = async (req, res, next) => {
try {
const token = req.header('Authorization')?.replace('Bearer ', '');
if (token) {
const decoded = jwt.verify(token, process.env.JWT_SECRET);
const user = await User.findByPk(decoded.id, {
include: [{
model: Role,
as: 'role'
}]
});
if (user && user.status === 'active') {
req.user = user;
}
}
next();
} catch (error) {
// 可选认证失败时不返回错误,继续执行
next();
}
};
/**
* 检查账户所有权
* @param {Object} req 请求对象
* @param {Object} res 响应对象
* @param {Function} next 下一个中间件
*/
const checkAccountOwnership = async (req, res, next) => {
try {
const { accountId } = req.params;
const userId = req.user.id;
// 管理员可以访问所有账户
if (req.user.role && req.user.role.name === 'admin') {
return next();
}
const { Account } = require('../models');
const account = await Account.findOne({
where: {
id: accountId,
user_id: userId
}
});
if (!account) {
return res.status(403).json({
success: false,
message: '无权访问该账户'
});
}
req.account = account;
next();
} catch (error) {
console.error('账户所有权检查错误:', error);
return res.status(500).json({
success: false,
message: '服务器内部错误'
});
}
};
module.exports = {
verifyToken,
requireRole,
requireLevel,
optionalAuth,
checkAccountOwnership
};