feat: 用户注册、登陆、退出接口

This commit is contained in:
luozhj33 2026-03-19 14:06:19 +08:00
parent 80929d6612
commit 2647de4455
2 changed files with 159 additions and 0 deletions

View File

@ -0,0 +1,144 @@
const mysql = require('../config/mysql');
const { generateToken, addTokenToBlacklist } = require('../middleware/jwt');
const { standardResponse } = require('../utils/standardResponse');
const crypto = require('crypto');
// 用户注册
async function register(req, res) {
console.log('POST /api/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 users 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 users (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/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 users 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/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
};

15
back/src/routes/user.js Normal file
View File

@ -0,0 +1,15 @@
const express = require('express');
const router = express.Router();
const { register, login, logout } = require('../controllers/user');
const { jwtAuth } = require('../middleware/jwt');
// 用户注册
router.post('/user/register', register);
// 用户登录
router.post('/user/login', login);
// 用户退出
router.post('/user/logout', jwtAuth, logout);
module.exports = router;