diff --git a/back/src/controllers/admin.js b/back/src/controllers/admin.js new file mode 100644 index 0000000..c1acb2b --- /dev/null +++ b/back/src/controllers/admin.js @@ -0,0 +1,144 @@ +const mysql = require('../config/mysql'); +const { generateToken, addTokenToBlacklist } = require('../middleware/jwt'); +const { standardResponse } = require('../utils/standardResponse'); +const crypto = require('crypto'); + +// 管理员注册(已关闭)// TODO +async function register(req, res) { + console.log('POST /api/admin/register'); // TODO + const { username, password, email, phone } = req.body; + + // 参数验证 + if (username == null || username === '') { + return res.status(400).json(standardResponse(400, '管理员名不能为空')); + } + if (password == null || password === '') { + return res.status(400).json(standardResponse(400, '密码不能为空')); + } + if ((email == null || email === '') && (phone == null || phone === '')) { + return res.status(400).json(standardResponse(400, '邮箱或手机号不能为空')); + } + + + try { + // 检查管理员名是否已存在 + const existingUser = await mysql.query( + 'SELECT id FROM admin WHERE username = ? AND is_deleted = 0', + [username] + ); + if (existingUser.length > 0) { + return res.status(400).json(standardResponse(400, '用户名已存在')); + } + + // 插入新用户 + const user_id = generateUserId(); + const salt = generateSalt(); + const hash = hashPassword(password, salt); + await mysql.query( + 'INSERT INTO admin (user_id, username, password, salt, email, phone) VALUES (?, ?, ?, ?, ?, ?)', + [user_id, username, hash, salt, email || null, phone || null] + ); + + return res.status(200).json( + standardResponse(200, '注册成功') + ); + } catch (error) { + console.error('注册失败:', error); // TODO + return res.status(500).json( + standardResponse(500, '注册失败') + ); + } +} + +// 管理员登录 +async function login(req, res) { + console.log('POST /api/admin/login'); // TODO + const { username, password } = req.body; + + // 参数验证 + if (username == null || username === '') { + return res.status(400).json(standardResponse(400, '管理员名不能为空')); + } + if (password == null || password === '') { + return res.status(400).json(standardResponse(400, '密码不能为空')); + } + + try { + // 查询用户(仅支持用户名登录) + const users = await mysql.query( + 'SELECT user_id, username, password, salt FROM admin WHERE username = ? AND is_deleted = 0', + [username] + ); + if (users.length === 0) { + return res.status(400).json(standardResponse(400, '用户不存在')); + } + + // 验证密码 + const user = users[0]; + const isValid = verifyPassword(password, user.salt, user.password); + if (!isValid) { + return res.status(400).json(standardResponse(400, '密码错误')); + } + + // 生成 jwt_token + const token = generateToken( + { user_id: user.user_id, username: user.username }, + '24h' + ); + + return res.status(200) + .set('Authorization', `Bearer ${token}`) + .json(standardResponse(200, '登录成功', { + user_id: user.user_id, + username: user.username, + email: user.email, + phone: user.phone + }) + ); + } catch (error) { + console.error('登录失败:', error); // TODO + return res.status(500).json(standardResponse(500, '登录失败')); + } +} + +// 管理员退出 +async function logout(req, res) { + console.log('POST /api/admin/logout'); // TODO + try { + // 将 token 加入黑名单 + const token = req.token; + await addTokenToBlacklist(token, 86400); // 24 小时 + return res.status(200).json(standardResponse(200, '退出成功')); + } catch (error) { + console.error('退出失败:', error); // TODO + return res.status(500).json(standardResponse(500, '退出失败')); + } +} + + +// 生成 user_id,通过时间和随机数生成,几乎不存在碰撞 +function generateUserId() { + return 'id_' + Date.now().toString(36) + '_' + Math.random().toString(36).slice(4, 8);; +} + +// 生成随机 salt +function generateSalt() { + return crypto.randomBytes(16).toString('hex'); +} + +// SHA256 + salt 加密密码 +function hashPassword(password, salt) { + return crypto.createHash('sha256').update(salt + password).digest('hex'); +} + +// 验证密码 +function verifyPassword(rawPassword, salt, databasePassword) { + const hash = hashPassword(rawPassword, salt); + return hash === databasePassword; +} + +module.exports = { + register, + login, + logout +}; \ No newline at end of file diff --git a/back/src/routes/admin.js b/back/src/routes/admin.js new file mode 100644 index 0000000..2fdae7a --- /dev/null +++ b/back/src/routes/admin.js @@ -0,0 +1,15 @@ +const express = require('express'); +const router = express.Router(); +const { register, login, logout } = require('../controllers/admin'); +const { jwtAuth } = require('../middleware/jwt'); + +// 管理员注册 +// router.post('/admin/register', register); + +// 管理员登录 +router.post('/admin/login', login); + +// 管理员退出 +router.post('/admin/logout', jwtAuth, logout); + +module.exports = router; \ No newline at end of file