v0.1.0
This commit is contained in:
39
middleware/auth.js
Normal file
39
middleware/auth.js
Normal file
@ -0,0 +1,39 @@
|
||||
const jwt = require('jsonwebtoken');
|
||||
|
||||
// 生成JWT token
|
||||
const generateToken = (userId, username) => {
|
||||
return jwt.sign(
|
||||
{ userId, username },
|
||||
process.env.JWT_SECRET || 'your_jwt_secret_key_here',
|
||||
{ expiresIn: '24h' }
|
||||
);
|
||||
};
|
||||
|
||||
// 验证JWT token中间件
|
||||
const authenticateToken = (req, res, next) => {
|
||||
const authHeader = req.headers['authorization'];
|
||||
const token = authHeader && authHeader.split(' ')[1]; // Bearer TOKEN
|
||||
|
||||
if (!token) {
|
||||
return res.status(401).json({
|
||||
success: false,
|
||||
message: '访问令牌缺失'
|
||||
});
|
||||
}
|
||||
|
||||
jwt.verify(token, process.env.JWT_SECRET || 'your_jwt_secret_key_here', (err, user) => {
|
||||
if (err) {
|
||||
return res.status(403).json({
|
||||
success: false,
|
||||
message: '访问令牌无效'
|
||||
});
|
||||
}
|
||||
req.user = user;
|
||||
next();
|
||||
});
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
generateToken,
|
||||
authenticateToken
|
||||
};
|
118
middleware/oauth.js
Normal file
118
middleware/oauth.js
Normal file
@ -0,0 +1,118 @@
|
||||
const OAuthToken = require('../models/OAuthToken');
|
||||
|
||||
// OAuth访问令牌验证中间件
|
||||
const authenticateOAuthToken = async (req, res, next) => {
|
||||
const authHeader = req.headers['authorization'];
|
||||
const token = authHeader && authHeader.split(' ')[1]; // Bearer TOKEN
|
||||
|
||||
if (!token) {
|
||||
return res.status(401).json({
|
||||
success: false,
|
||||
message: '访问令牌缺失'
|
||||
});
|
||||
}
|
||||
|
||||
try {
|
||||
const tokenData = await OAuthToken.validateAccessToken(token);
|
||||
if (!tokenData) {
|
||||
return res.status(401).json({
|
||||
success: false,
|
||||
message: '访问令牌无效或已过期'
|
||||
});
|
||||
}
|
||||
|
||||
req.oauth = {
|
||||
token: tokenData.token,
|
||||
clientId: tokenData.client_id,
|
||||
userId: tokenData.user_id,
|
||||
scopes: tokenData.scopes,
|
||||
username: tokenData.username,
|
||||
email: tokenData.email
|
||||
};
|
||||
next();
|
||||
} catch (error) {
|
||||
console.error('OAuth令牌验证失败:', error);
|
||||
return res.status(500).json({
|
||||
success: false,
|
||||
message: '服务器内部错误'
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
// 检查OAuth权限范围
|
||||
const requireScope = (requiredScope) => {
|
||||
return (req, res, next) => {
|
||||
if (!req.oauth) {
|
||||
return res.status(401).json({
|
||||
success: false,
|
||||
message: '需要OAuth认证'
|
||||
});
|
||||
}
|
||||
|
||||
if (!req.oauth.scopes.includes(requiredScope)) {
|
||||
return res.status(403).json({
|
||||
success: false,
|
||||
message: `需要权限范围: ${requiredScope}`
|
||||
});
|
||||
}
|
||||
|
||||
next();
|
||||
};
|
||||
};
|
||||
|
||||
// 检查多个权限范围(任一即可)
|
||||
const requireAnyScope = (requiredScopes) => {
|
||||
return (req, res, next) => {
|
||||
if (!req.oauth) {
|
||||
return res.status(401).json({
|
||||
success: false,
|
||||
message: '需要OAuth认证'
|
||||
});
|
||||
}
|
||||
|
||||
const hasAnyScope = requiredScopes.some(scope =>
|
||||
req.oauth.scopes.includes(scope)
|
||||
);
|
||||
|
||||
if (!hasAnyScope) {
|
||||
return res.status(403).json({
|
||||
success: false,
|
||||
message: `需要权限范围: ${requiredScopes.join(' 或 ')}`
|
||||
});
|
||||
}
|
||||
|
||||
next();
|
||||
};
|
||||
};
|
||||
|
||||
// 检查所有权限范围
|
||||
const requireAllScopes = (requiredScopes) => {
|
||||
return (req, res, next) => {
|
||||
if (!req.oauth) {
|
||||
return res.status(401).json({
|
||||
success: false,
|
||||
message: '需要OAuth认证'
|
||||
});
|
||||
}
|
||||
|
||||
const hasAllScopes = requiredScopes.every(scope =>
|
||||
req.oauth.scopes.includes(scope)
|
||||
);
|
||||
|
||||
if (!hasAllScopes) {
|
||||
return res.status(403).json({
|
||||
success: false,
|
||||
message: `需要所有权限范围: ${requiredScopes.join(', ')}`
|
||||
});
|
||||
}
|
||||
|
||||
next();
|
||||
};
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
authenticateOAuthToken,
|
||||
requireScope,
|
||||
requireAnyScope,
|
||||
requireAllScopes
|
||||
};
|
56
middleware/validation.js
Normal file
56
middleware/validation.js
Normal file
@ -0,0 +1,56 @@
|
||||
const { body, validationResult } = require('express-validator');
|
||||
|
||||
// 注册验证规则
|
||||
const registerValidation = [
|
||||
body('username')
|
||||
.isLength({ min: 3, max: 50 })
|
||||
.withMessage('用户名长度必须在3-50个字符之间')
|
||||
.matches(/^[a-zA-Z0-9_]+$/)
|
||||
.withMessage('用户名只能包含字母、数字和下划线'),
|
||||
|
||||
body('email')
|
||||
.isEmail()
|
||||
.withMessage('请输入有效的邮箱地址')
|
||||
.normalizeEmail(),
|
||||
|
||||
body('password')
|
||||
.isLength({ min: 6 })
|
||||
.withMessage('密码长度至少6个字符')
|
||||
.matches(/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)/)
|
||||
.withMessage('密码必须包含至少一个小写字母、一个大写字母和一个数字')
|
||||
];
|
||||
|
||||
// 登录验证规则
|
||||
const loginValidation = [
|
||||
body('username')
|
||||
.notEmpty()
|
||||
.withMessage('用户名不能为空'),
|
||||
|
||||
body('password')
|
||||
.notEmpty()
|
||||
.withMessage('密码不能为空')
|
||||
];
|
||||
|
||||
// 验证结果处理中间件
|
||||
const handleValidationErrors = (req, res, next) => {
|
||||
const errors = validationResult(req);
|
||||
// console.log(req.body);
|
||||
|
||||
if (!errors.isEmpty()) {
|
||||
return res.status(400).json({
|
||||
success: false,
|
||||
message: '输入验证失败',
|
||||
errors: errors.array().map(error => ({
|
||||
field: error.path,
|
||||
message: error.msg
|
||||
}))
|
||||
});
|
||||
}
|
||||
next();
|
||||
};
|
||||
|
||||
module.exports = {
|
||||
registerValidation,
|
||||
loginValidation,
|
||||
handleValidationErrors
|
||||
};
|
Reference in New Issue
Block a user