Files
niumalll/backend/routes/auth.js
2025-09-04 09:04:58 +08:00

186 lines
4.7 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

const express = require('express');
const router = express.Router();
const Joi = require('joi');
const User = require('../models/User');
const { generateToken, refreshToken, authenticateToken } = require('../middleware/auth');
// 验证schema
const loginSchema = Joi.object({
username: Joi.string().min(2).max(50).required(),
password: Joi.string().min(6).max(100).required()
});
const passwordResetRequestSchema = Joi.object({
phone: Joi.string().pattern(/^1[3-9]\d{9}$/).required()
});
const passwordResetConfirmSchema = Joi.object({
phone: Joi.string().pattern(/^1[3-9]\d{9}$/).required(),
resetCode: Joi.string().required(),
newPassword: Joi.string().min(6).max(100).required()
});
const changePasswordSchema = Joi.object({
oldPassword: Joi.string().required(),
newPassword: Joi.string().min(6).max(100).required()
});
// 用户登录
router.post('/login', async (req, res) => {
try {
const { error, value } = loginSchema.validate(req.body);
if (error) {
return res.status(400).json({
success: false,
message: '参数验证失败',
errors: error.details.map(detail => detail.message)
});
}
const { username, password } = value;
// 查找用户
const user = await User.findByLoginIdentifier(username);
if (!user) {
return res.status(401).json({
success: false,
message: '用户名或密码错误',
code: 'INVALID_CREDENTIALS'
});
}
// 验证密码
const isValidPassword = await user.validatePassword(password);
if (!isValidPassword) {
return res.status(401).json({
success: false,
message: '用户名或密码错误',
code: 'INVALID_CREDENTIALS'
});
}
if (user.status !== 'active') {
return res.status(401).json({
success: false,
message: '账号已被禁用,请联系管理员',
code: 'ACCOUNT_DISABLED'
});
}
// 更新登录信息
await user.updateLoginInfo();
// 生成JWT token
const tokens = generateToken(user);
res.json({
success: true,
message: '登录成功',
data: {
...tokens,
user: {
id: user.id,
uuid: user.uuid,
username: user.username,
phone: user.phone,
email: user.email,
real_name: user.real_name,
avatar_url: user.avatar_url,
user_type: user.user_type,
status: user.status,
last_login_at: user.last_login_at,
login_count: user.login_count
}
}
});
} catch (error) {
console.error('登录错误:', error);
res.status(500).json({
success: false,
message: '登录失败',
error: error.message
});
}
});
// 获取用户信息
router.get('/me', authenticateToken, async (req, res) => {
try {
// req.user 已经通过中间件注入
res.json({
success: true,
data: {
id: req.user.id,
uuid: req.user.uuid,
username: req.user.username,
phone: req.user.phone,
email: req.user.email,
real_name: req.user.real_name,
avatar_url: req.user.avatar_url,
user_type: req.user.user_type,
status: req.user.status,
last_login_at: req.user.last_login_at,
login_count: req.user.login_count,
created_at: req.user.created_at,
updated_at: req.user.updated_at
}
});
} catch (error) {
console.error('获取用户信息错误:', error);
res.status(500).json({
success: false,
message: '获取用户信息失败',
error: error.message
});
}
});
// 用户登出
router.post('/logout', authenticateToken, async (req, res) => {
try {
// TODO: 实际项目中可以将token加入黑名单或Redis
res.json({
success: true,
message: '退出登录成功'
});
} catch (error) {
console.error('退出登录错误:', error);
res.status(500).json({
success: false,
message: '退出登录失败',
error: error.message
});
}
});
// 刷新token
router.post('/refresh', refreshToken);
// 验证token有效性
router.post('/verify', authenticateToken, (req, res) => {
try {
// 如果通过认证中间件说明token有效
res.json({
success: true,
message: 'Token有效',
data: {
valid: true,
user: {
id: req.user.id,
username: req.user.username,
user_type: req.user.user_type
}
}
});
} catch (error) {
console.error('Token验证错误:', error);
res.status(500).json({
success: false,
message: 'Token验证失败',
error: error.message
});
}
});
module.exports = router;