first commit
This commit is contained in:
249
api/routes/auth.ts
Executable file
249
api/routes/auth.ts
Executable file
@@ -0,0 +1,249 @@
|
||||
/**
|
||||
* 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;
|
||||
Reference in New Issue
Block a user