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 { authenticateJWT } = require('../middleware/auth') /** * @swagger * components: * schemas: * LoginRequest: * type: object * required: * - username * - password * properties: * username: * type: string * description: 用户名 * password: * type: string * description: 密码 * LoginResponse: * type: object * properties: * success: * type: boolean * message: * type: string * token: * type: string * user: * type: object * properties: * id: * type: integer * username: * type: string * email: * type: string * user_type: * type: string * status: * type: string */ // 从环境变量或配置中获取JWT密钥 const JWT_SECRET = process.env.JWT_SECRET || 'your_jwt_secret_key' const JWT_EXPIRES_IN = process.env.JWT_EXPIRES_IN || '24h' // 验证模式 const loginSchema = Joi.object({ username: Joi.string().required(), password: Joi.string().required() }) // 生成JWT令牌 const generateToken = (user) => { return jwt.sign( { id: user.id, username: user.username, email: user.email, user_type: user.user_type }, JWT_SECRET, { expiresIn: JWT_EXPIRES_IN } ) } /** * @swagger * /api/auth/login: * post: * summary: 用户登录 * tags: [认证管理] * requestBody: * required: true * content: * application/json: * schema: * $ref: '#/components/schemas/LoginRequest' * responses: * 200: * description: 登录成功 * content: * application/json: * schema: * $ref: '#/components/schemas/LoginResponse' * 400: * description: 参数验证失败或用户名密码错误 * 401: * description: 未授权或用户被禁用 * 500: * description: 服务器内部错误 */ // 用户登录 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: { [ApiUser.sequelize.Op.or]: [ { username }, { email: username } ] } }) // 检查用户是否存在以及密码是否正确 if (!user || !(await bcrypt.compare(password, user.password_hash))) { return res.status(401).json({ success: false, message: '用户名或密码错误' }) } // 检查用户状态 if (user.status !== 'active') { return res.status(401).json({ success: false, message: '用户账号已被禁用' }) } // 生成JWT令牌 const token = generateToken(user) // 准备返回的用户信息(不包含敏感数据) const userInfo = { id: user.id, username: user.username, email: user.email, user_type: user.user_type, status: user.status } res.json({ success: true, message: '登录成功', token, user: userInfo }) } catch (error) { console.error('用户登录失败:', error) res.status(500).json({ success: false, message: '登录失败,请稍后再试' }) } }) /** * @swagger * /api/auth/me: * get: * summary: 获取当前用户信息 * tags: [认证管理] * security: * - bearerAuth: [] * responses: * 200: * description: 获取成功 * content: * application/json: * schema: * type: object * properties: * success: * type: boolean * data: * type: object * properties: * id: * type: integer * username: * type: string * email: * type: string * user_type: * type: string * status: * type: string * createdAt: * type: string * format: date-time * updatedAt: * type: string * format: date-time * 401: * description: 未授权 * 500: * description: 服务器内部错误 */ // 获取当前用户信息 router.get('/me', authenticateJWT, async (req, res) => { try { const userId = req.user.id // 根据ID查找用户 const user = await ApiUser.findByPk(userId, { attributes: { exclude: ['password_hash'] // 排除密码哈希等敏感信息 } }) if (!user) { return res.status(404).json({ success: false, message: '用户不存在' }) } res.json({ success: true, data: user }) } catch (error) { console.error('获取用户信息失败:', error) res.status(500).json({ success: false, message: '获取用户信息失败' }) } }) /** * @swagger * /api/auth/logout: * post: * summary: 用户登出 * tags: [认证管理] * security: * - bearerAuth: [] * responses: * 200: * description: 登出成功 * content: * application/json: * schema: * type: object * properties: * success: * type: boolean * message: * type: string * 401: * description: 未授权 * 500: * description: 服务器内部错误 */ // 用户登出 router.post('/logout', authenticateJWT, async (req, res) => { try { // 注意:JWT是无状态的,服务器端无法直接使token失效 // 登出操作主要由客户端完成,如删除本地存储的token // 这里只返回成功信息 res.json({ success: true, message: '登出成功' }) } catch (error) { console.error('用户登出失败:', error) res.status(500).json({ success: false, message: '登出失败,请稍后再试' }) } }) module.exports = router