Files
niumalll/backend/routes/auth.js

172 lines
3.8 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 bcrypt = require('bcryptjs')
const jwt = require('jsonwebtoken')
const Joi = require('joi')
const router = express.Router()
// 引入数据库模型
const { ApiUser } = require('../models')
// 登录参数验证
const loginSchema = Joi.object({
username: Joi.string().min(2).max(50).required(),
password: Joi.string().min(6).max(100).required()
})
// 生成JWT token
const generateToken = (user) => {
return jwt.sign(
{
id: user.id,
username: user.username,
role: user.user_type
},
process.env.JWT_SECRET || 'niumall-secret-key',
{ expiresIn: process.env.JWT_EXPIRES_IN || '24h' }
)
}
// 用户登录
router.post('/login', async (req, res) => {
try {
// 参数验证
const { error, value } = loginSchema.validate(req.body)
if (error) {
return res.status(400).json({
success: false,
message: '参数验证失败',
details: error.details[0].message
})
}
const { username, password } = value
// 查找用户
const user = await ApiUser.findOne({
where: {
[require('sequelize').Op.or]: [
{ username: username },
{ phone: username },
{ email: username }
]
}
});
if (!user) {
return res.status(401).json({
success: false,
message: '用户名或密码错误'
})
}
// 验证密码
const isPasswordValid = await bcrypt.compare(password, user.password_hash)
if (!isPasswordValid) {
return res.status(401).json({
success: false,
message: '用户名或密码错误'
})
}
// 检查用户状态
if (user.status !== 'active') {
return res.status(403).json({
success: false,
message: '账户已被禁用,请联系管理员'
})
}
// 生成token
const token = generateToken(user)
res.json({
success: true,
message: '登录成功',
data: {
access_token: token,
token_type: 'Bearer',
expires_in: 86400, // 24小时
user: {
id: user.id,
username: user.username,
email: user.email,
role: user.user_type,
status: user.status
}
}
})
} catch (error) {
console.error('登录失败:', error)
res.status(500).json({
success: false,
message: '登录失败,请稍后重试'
})
}
})
// 获取当前用户信息
router.get('/me', authenticateToken, async (req, res) => {
try {
const user = await ApiUser.findByPk(req.user.id)
if (!user) {
return res.status(404).json({
success: false,
message: '用户不存在'
})
}
res.json({
success: true,
data: {
user: {
id: user.id,
username: user.username,
email: user.email,
role: user.user_type,
status: user.status
}
}
})
} catch (error) {
console.error('获取用户信息失败:', error)
res.status(500).json({
success: false,
message: '获取用户信息失败'
})
}
})
// 用户登出
router.post('/logout', authenticateToken, (req, res) => {
// 在实际项目中可以将token加入黑名单
res.json({
success: true,
message: '登出成功'
})
})
// JWT token验证中间件
function authenticateToken(req, res, next) {
const authHeader = req.headers['authorization']
const token = authHeader && authHeader.split(' ')[1]
if (!token) {
return res.status(401).json({
success: false,
message: '访问令牌缺失'
})
}
jwt.verify(token, process.env.JWT_SECRET || 'niumall-secret-key', (err, user) => {
if (err) {
return res.status(403).json({
success: false,
message: '访问令牌无效或已过期'
})
}
req.user = user
next()
})
}
module.exports = router