249 lines
5.5 KiB
TypeScript
Executable File
249 lines
5.5 KiB
TypeScript
Executable File
/**
|
||
* This is a user authentication API route.
|
||
* Handle user registration, login, token management, etc.
|
||
*/
|
||
import { Router, type Request, type Response } from 'express';
|
||
import bcrypt from 'bcrypt';
|
||
import jwt from 'jsonwebtoken';
|
||
import { query, queryOne, execute } from '../config/database.js';
|
||
|
||
const router = Router();
|
||
|
||
// JWT密钥
|
||
const JWT_SECRET = process.env.JWT_SECRET || 'your-secret-key';
|
||
|
||
/**
|
||
* User Registration
|
||
* POST /api/auth/register
|
||
*/
|
||
router.post('/register', async (req: Request, res: Response): Promise<void> => {
|
||
try {
|
||
const { username, email, password } = req.body;
|
||
|
||
// 验证输入
|
||
if (!username || !email || !password) {
|
||
res.status(400).json({
|
||
success: false,
|
||
message: '用户名、邮箱和密码都是必填项'
|
||
});
|
||
return;
|
||
}
|
||
|
||
// 检查用户是否已存在
|
||
const existingUser = await queryOne(
|
||
'SELECT id FROM users WHERE username = ? OR email = ?',
|
||
[username, email]
|
||
);
|
||
|
||
if (existingUser) {
|
||
res.status(400).json({
|
||
success: false,
|
||
message: '用户名或邮箱已存在'
|
||
});
|
||
return;
|
||
}
|
||
|
||
// 加密密码
|
||
const hashedPassword = await bcrypt.hash(password, 10);
|
||
|
||
// 插入新用户
|
||
const result = await execute(
|
||
'INSERT INTO users (username, email, password, created_at) VALUES (?, ?, ?, datetime("now"))',
|
||
[username, email, hashedPassword]
|
||
);
|
||
|
||
res.status(201).json({
|
||
success: true,
|
||
message: '用户注册成功',
|
||
data: {
|
||
id: result.lastID,
|
||
username,
|
||
email
|
||
}
|
||
});
|
||
} catch (error) {
|
||
console.error('注册失败:', error);
|
||
res.status(500).json({
|
||
success: false,
|
||
message: '服务器内部错误'
|
||
});
|
||
}
|
||
});
|
||
|
||
/**
|
||
* User Login
|
||
* POST /api/auth/login
|
||
*/
|
||
router.post('/login', async (req: Request, res: Response): Promise<void> => {
|
||
try {
|
||
const { username, password } = req.body;
|
||
|
||
// 验证输入
|
||
if (!username || !password) {
|
||
res.status(400).json({
|
||
success: false,
|
||
message: '用户名和密码都是必填项'
|
||
});
|
||
return;
|
||
}
|
||
|
||
// 查找用户
|
||
const user = await queryOne(
|
||
'SELECT id, username, email, password, role FROM users WHERE username = ? OR email = ?',
|
||
[username, username]
|
||
);
|
||
|
||
if (!user) {
|
||
res.status(401).json({
|
||
success: false,
|
||
message: '用户名或密码错误'
|
||
});
|
||
return;
|
||
}
|
||
|
||
// 验证密码
|
||
const isValidPassword = await bcrypt.compare(password, user.password);
|
||
if (!isValidPassword) {
|
||
res.status(401).json({
|
||
success: false,
|
||
message: '用户名或密码错误'
|
||
});
|
||
return;
|
||
}
|
||
|
||
// 生成JWT token
|
||
const token = jwt.sign(
|
||
{
|
||
id: user.id,
|
||
username: user.username,
|
||
email: user.email,
|
||
role: user.role
|
||
},
|
||
JWT_SECRET,
|
||
{ expiresIn: '24h' }
|
||
);
|
||
|
||
res.json({
|
||
success: true,
|
||
message: '登录成功',
|
||
data: {
|
||
token,
|
||
user: {
|
||
id: user.id,
|
||
username: user.username,
|
||
email: user.email,
|
||
role: user.role
|
||
}
|
||
}
|
||
});
|
||
} catch (error) {
|
||
console.error('登录失败:', error);
|
||
res.status(500).json({
|
||
success: false,
|
||
message: '服务器内部错误'
|
||
});
|
||
}
|
||
});
|
||
|
||
/**
|
||
* Token Refresh
|
||
* POST /api/auth/refresh
|
||
*/
|
||
router.post('/refresh', async (req: Request, res: Response): Promise<void> => {
|
||
try {
|
||
const authHeader = req.headers['authorization'];
|
||
const token = authHeader && authHeader.split(' ')[1];
|
||
|
||
if (!token) {
|
||
res.status(401).json({
|
||
success: false,
|
||
message: '访问令牌缺失'
|
||
});
|
||
return;
|
||
}
|
||
|
||
// 验证当前token(即使过期也要能解析出用户信息)
|
||
let decoded: any;
|
||
try {
|
||
decoded = jwt.verify(token, JWT_SECRET);
|
||
} catch (error: any) {
|
||
// 如果是过期错误,尝试解析过期的token
|
||
if (error.name === 'TokenExpiredError') {
|
||
decoded = jwt.decode(token);
|
||
if (!decoded) {
|
||
res.status(401).json({
|
||
success: false,
|
||
message: '无效的访问令牌'
|
||
});
|
||
return;
|
||
}
|
||
} else {
|
||
res.status(401).json({
|
||
success: false,
|
||
message: '无效的访问令牌'
|
||
});
|
||
return;
|
||
}
|
||
}
|
||
|
||
// 验证用户是否仍然存在
|
||
const user = await queryOne(
|
||
'SELECT id, username, email, role FROM users WHERE id = ?',
|
||
[decoded.id]
|
||
);
|
||
|
||
if (!user) {
|
||
res.status(401).json({
|
||
success: false,
|
||
message: '用户不存在'
|
||
});
|
||
return;
|
||
}
|
||
|
||
// 生成新的JWT token
|
||
const newToken = jwt.sign(
|
||
{
|
||
id: user.id,
|
||
username: user.username,
|
||
email: user.email,
|
||
role: user.role
|
||
},
|
||
JWT_SECRET,
|
||
{ expiresIn: '24h' }
|
||
);
|
||
|
||
res.json({
|
||
success: true,
|
||
message: 'Token刷新成功',
|
||
data: {
|
||
token: newToken,
|
||
user: {
|
||
id: user.id,
|
||
username: user.username,
|
||
email: user.email,
|
||
role: user.role
|
||
}
|
||
}
|
||
});
|
||
} catch (error) {
|
||
console.error('Token刷新失败:', error);
|
||
res.status(500).json({
|
||
success: false,
|
||
message: '服务器内部错误'
|
||
});
|
||
}
|
||
});
|
||
|
||
/**
|
||
* User Logout
|
||
* POST /api/auth/logout
|
||
*/
|
||
router.post('/logout', async (req: Request, res: Response): Promise<void> => {
|
||
// 由于使用JWT,logout主要在前端处理(删除token)
|
||
res.json({
|
||
success: true,
|
||
message: '退出登录成功'
|
||
});
|
||
});
|
||
|
||
export default router; |