feat: 用户注册、登陆、退出接口
This commit is contained in:
parent
80929d6612
commit
2647de4455
144
back/src/controllers/user.js
Normal file
144
back/src/controllers/user.js
Normal 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
15
back/src/routes/user.js
Normal 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;
|
||||
Loading…
x
Reference in New Issue
Block a user