223 lines
5.7 KiB
JavaScript
223 lines
5.7 KiB
JavaScript
const express = require('express');
|
|
const bcrypt = require('bcryptjs');
|
|
const jwt = require('jsonwebtoken');
|
|
const db = require('../config/database');
|
|
|
|
const router = express.Router();
|
|
|
|
// 用户注册
|
|
router.post('/register', async (req, res) => {
|
|
try {
|
|
const { email, phone, password } = req.body;
|
|
|
|
// 验证输入
|
|
if (!email || !password) {
|
|
return res.status(400).json({ error: '邮箱和密码是必填项' });
|
|
}
|
|
|
|
if (password.length < 6) {
|
|
return res.status(400).json({ error: '密码长度至少6位' });
|
|
}
|
|
|
|
// 检查用户是否已存在
|
|
const [existingUsers] = await db.pool.execute(
|
|
'SELECT id FROM users WHERE email = ?',
|
|
[email]
|
|
);
|
|
|
|
if (existingUsers.length > 0) {
|
|
return res.status(400).json({ error: '该邮箱已被注册' });
|
|
}
|
|
|
|
// 加密密码
|
|
const saltRounds = 12;
|
|
const passwordHash = await bcrypt.hash(password, saltRounds);
|
|
|
|
// 创建用户
|
|
const [result] = await db.pool.execute(
|
|
'INSERT INTO users (email, phone, password_hash) VALUES (?, ?, ?)',
|
|
[email, phone || null, passwordHash]
|
|
);
|
|
|
|
// 生成JWT令牌
|
|
const token = jwt.sign(
|
|
{ userId: result.insertId, email },
|
|
process.env.JWT_SECRET || 'webssh-secret-key',
|
|
{ expiresIn: '7d' }
|
|
);
|
|
|
|
res.status(201).json({
|
|
message: '注册成功',
|
|
token,
|
|
user: {
|
|
id: result.insertId,
|
|
email,
|
|
phone
|
|
}
|
|
});
|
|
} catch (error) {
|
|
console.error('注册错误:', error);
|
|
res.status(500).json({ error: '服务器内部错误' });
|
|
}
|
|
});
|
|
|
|
// 用户登录
|
|
router.post('/login', async (req, res) => {
|
|
try {
|
|
const { email, password } = req.body;
|
|
|
|
if (!email || !password) {
|
|
return res.status(400).json({ error: '邮箱和密码是必填项' });
|
|
}
|
|
|
|
// 查找用户
|
|
const [users] = await db.pool.execute(
|
|
'SELECT * FROM users WHERE email = ?',
|
|
[email]
|
|
);
|
|
|
|
if (users.length === 0) {
|
|
return res.status(401).json({ error: '邮箱或密码错误' });
|
|
}
|
|
|
|
const user = users[0];
|
|
|
|
// 检查用户是否激活
|
|
if (user.is_active !== 1) {
|
|
return res.status(403).json({ error: '账户已被禁用,请联系管理员' });
|
|
}
|
|
|
|
// 验证密码
|
|
const isValidPassword = await bcrypt.compare(password, user.password_hash);
|
|
if (!isValidPassword) {
|
|
return res.status(401).json({ error: '邮箱或密码错误' });
|
|
}
|
|
|
|
// 更新最后登录时间
|
|
await db.pool.execute(
|
|
'UPDATE users SET last_login = CURRENT_TIMESTAMP WHERE id = ?',
|
|
[user.id]
|
|
);
|
|
|
|
// 生成JWT令牌(包含管理员信息)
|
|
const token = jwt.sign(
|
|
{
|
|
userId: user.id,
|
|
email: user.email,
|
|
isAdmin: user.is_admin === 1
|
|
},
|
|
process.env.JWT_SECRET || 'webssh-secret-key',
|
|
{ expiresIn: '7d' }
|
|
);
|
|
|
|
res.json({
|
|
message: '登录成功',
|
|
token,
|
|
user: {
|
|
id: user.id,
|
|
email: user.email,
|
|
phone: user.phone,
|
|
is_admin: user.is_admin === 1
|
|
}
|
|
});
|
|
} catch (error) {
|
|
console.error('登录错误:', error);
|
|
res.status(500).json({ error: '服务器内部错误' });
|
|
}
|
|
});
|
|
|
|
// 验证令牌中间件
|
|
const authenticateToken = (req, res, next) => {
|
|
const authHeader = req.headers['authorization'];
|
|
const token = authHeader && authHeader.split(' ')[1];
|
|
|
|
if (!token) {
|
|
return res.status(401).json({ error: '访问令牌缺失' });
|
|
}
|
|
|
|
jwt.verify(token, process.env.JWT_SECRET || 'webssh-secret-key', (err, user) => {
|
|
if (err) {
|
|
return res.status(403).json({ error: '令牌无效' });
|
|
}
|
|
req.user = user;
|
|
next();
|
|
});
|
|
};
|
|
|
|
// 获取当前用户信息
|
|
router.get('/me', authenticateToken, async (req, res) => {
|
|
try {
|
|
const [users] = await db.pool.execute(
|
|
'SELECT id, email, phone, is_admin, is_active, last_login, created_at FROM users WHERE id = ?',
|
|
[req.user.userId]
|
|
);
|
|
|
|
if (users.length === 0) {
|
|
return res.status(404).json({ error: '用户不存在' });
|
|
}
|
|
|
|
const user = users[0];
|
|
res.json({
|
|
user: {
|
|
id: user.id,
|
|
email: user.email,
|
|
phone: user.phone,
|
|
is_admin: user.is_admin === 1,
|
|
is_active: user.is_active === 1,
|
|
last_login: user.last_login,
|
|
created_at: user.created_at
|
|
}
|
|
});
|
|
} catch (error) {
|
|
console.error('获取用户信息错误:', error);
|
|
res.status(500).json({ error: '服务器内部错误' });
|
|
}
|
|
});
|
|
|
|
// 修改密码
|
|
router.put('/password', authenticateToken, async (req, res) => {
|
|
try {
|
|
const { currentPassword, newPassword } = req.body;
|
|
|
|
if (!currentPassword || !newPassword) {
|
|
return res.status(400).json({ error: '当前密码和新密码是必填项' });
|
|
}
|
|
|
|
if (newPassword.length < 6) {
|
|
return res.status(400).json({ error: '新密码长度至少6位' });
|
|
}
|
|
|
|
// 获取用户当前密码
|
|
const [users] = await db.pool.execute(
|
|
'SELECT password_hash FROM users WHERE id = ?',
|
|
[req.user.userId]
|
|
);
|
|
|
|
if (users.length === 0) {
|
|
return res.status(404).json({ error: '用户不存在' });
|
|
}
|
|
|
|
// 验证当前密码
|
|
const isValidPassword = await bcrypt.compare(currentPassword, users[0].password_hash);
|
|
if (!isValidPassword) {
|
|
return res.status(401).json({ error: '当前密码错误' });
|
|
}
|
|
|
|
// 加密新密码
|
|
const saltRounds = 12;
|
|
const newPasswordHash = await bcrypt.hash(newPassword, saltRounds);
|
|
|
|
// 更新密码
|
|
await db.pool.execute(
|
|
'UPDATE users SET password_hash = ? WHERE id = ?',
|
|
[newPasswordHash, req.user.userId]
|
|
);
|
|
|
|
res.json({ message: '密码修改成功' });
|
|
} catch (error) {
|
|
console.error('修改密码错误:', error);
|
|
res.status(500).json({ error: '服务器内部错误' });
|
|
}
|
|
});
|
|
|
|
module.exports = router; |