mirror of
https://github.com/patdelphi/suanming.git
synced 2026-02-28 05:33:11 +08:00
feat: 完成从Supabase到本地化架构的迁移\n\n- 添加本地SQLite数据库支持\n- 实现本地认证系统(JWT + bcrypt)\n- 创建Express.js API服务器\n- 实现完整的命理分析算法\n- 替换Supabase客户端为本地API客户端\n- 保持前端接口兼容性\n- 添加本地服务器启动脚本
This commit is contained in:
231
server/routes/auth.js
Normal file
231
server/routes/auth.js
Normal file
@@ -0,0 +1,231 @@
|
||||
import express from 'express';
|
||||
import { authService } from '../services/authService.js';
|
||||
import { authenticateToken, rateLimit } from '../middleware/auth.js';
|
||||
|
||||
const router = express.Router();
|
||||
|
||||
// 应用速率限制
|
||||
router.use(rateLimit({ max: 20, windowMs: 15 * 60 * 1000 })); // 15分钟内最多20次请求
|
||||
|
||||
/**
|
||||
* 用户注册
|
||||
* POST /api/auth/signup
|
||||
*/
|
||||
router.post('/signup', async (req, res, next) => {
|
||||
try {
|
||||
const { email, password, fullName, birthDate, birthTime, birthPlace, gender } = req.body;
|
||||
|
||||
// 基本验证
|
||||
if (!email || !password) {
|
||||
return res.status(400).json({
|
||||
error: {
|
||||
code: 'MISSING_PARAMETERS',
|
||||
message: '邮箱和密码不能为空'
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 邮箱格式验证
|
||||
const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
|
||||
if (!emailRegex.test(email)) {
|
||||
return res.status(400).json({
|
||||
error: {
|
||||
code: 'INVALID_EMAIL',
|
||||
message: '邮箱格式不正确'
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// 密码强度验证
|
||||
if (password.length < 6) {
|
||||
return res.status(400).json({
|
||||
error: {
|
||||
code: 'WEAK_PASSWORD',
|
||||
message: '密码长度至少6位'
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const result = await authService.signUp({
|
||||
email,
|
||||
password,
|
||||
fullName,
|
||||
birthDate,
|
||||
birthTime,
|
||||
birthPlace,
|
||||
gender
|
||||
});
|
||||
|
||||
res.status(201).json({
|
||||
data: result,
|
||||
message: '注册成功'
|
||||
});
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* 用户登录
|
||||
* POST /api/auth/signin
|
||||
*/
|
||||
router.post('/signin', async (req, res, next) => {
|
||||
try {
|
||||
const { email, password } = req.body;
|
||||
|
||||
if (!email || !password) {
|
||||
return res.status(400).json({
|
||||
error: {
|
||||
code: 'MISSING_PARAMETERS',
|
||||
message: '邮箱和密码不能为空'
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const result = await authService.signIn(email, password);
|
||||
|
||||
res.json({
|
||||
data: result,
|
||||
message: '登录成功'
|
||||
});
|
||||
} catch (error) {
|
||||
if (error.message.includes('邮箱或密码错误')) {
|
||||
return res.status(401).json({
|
||||
error: {
|
||||
code: 'INVALID_CREDENTIALS',
|
||||
message: error.message
|
||||
}
|
||||
});
|
||||
}
|
||||
next(error);
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* 获取当前用户信息
|
||||
* GET /api/auth/user
|
||||
*/
|
||||
router.get('/user', authenticateToken, async (req, res, next) => {
|
||||
try {
|
||||
const user = await authService.getUserById(req.user.userId);
|
||||
|
||||
res.json({
|
||||
data: { user },
|
||||
message: '获取用户信息成功'
|
||||
});
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* 更新用户信息
|
||||
* PUT /api/auth/user
|
||||
*/
|
||||
router.put('/user', authenticateToken, async (req, res, next) => {
|
||||
try {
|
||||
const { fullName, birthDate, birthTime, birthPlace, gender } = req.body;
|
||||
|
||||
const updatedUser = await authService.updateUser(req.user.userId, {
|
||||
fullName,
|
||||
birthDate,
|
||||
birthTime,
|
||||
birthPlace,
|
||||
gender
|
||||
});
|
||||
|
||||
res.json({
|
||||
data: { user: updatedUser },
|
||||
message: '用户信息更新成功'
|
||||
});
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* 验证token
|
||||
* POST /api/auth/verify
|
||||
*/
|
||||
router.post('/verify', async (req, res, next) => {
|
||||
try {
|
||||
const { token } = req.body;
|
||||
|
||||
if (!token) {
|
||||
return res.status(400).json({
|
||||
error: {
|
||||
code: 'MISSING_TOKEN',
|
||||
message: 'Token不能为空'
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
const decoded = authService.verifyToken(token);
|
||||
const user = await authService.getUserById(decoded.userId);
|
||||
|
||||
res.json({
|
||||
data: { user, valid: true },
|
||||
message: 'Token验证成功'
|
||||
});
|
||||
} catch (error) {
|
||||
res.status(401).json({
|
||||
error: {
|
||||
code: 'INVALID_TOKEN',
|
||||
message: 'Token无效或已过期'
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* 用户登出(客户端处理,服务端记录日志)
|
||||
* POST /api/auth/signout
|
||||
*/
|
||||
router.post('/signout', authenticateToken, async (req, res) => {
|
||||
try {
|
||||
// 这里可以添加登出日志记录
|
||||
console.log(`用户 ${req.user.userId} 于 ${new Date().toISOString()} 登出`);
|
||||
|
||||
res.json({
|
||||
message: '登出成功'
|
||||
});
|
||||
} catch (error) {
|
||||
res.status(500).json({
|
||||
error: {
|
||||
code: 'SIGNOUT_ERROR',
|
||||
message: '登出失败'
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
/**
|
||||
* 刷新token(可选功能)
|
||||
* POST /api/auth/refresh
|
||||
*/
|
||||
router.post('/refresh', authenticateToken, async (req, res, next) => {
|
||||
try {
|
||||
const user = await authService.getUserById(req.user.userId);
|
||||
|
||||
// 生成新的token
|
||||
const jwt = await import('jsonwebtoken');
|
||||
const JWT_SECRET = process.env.JWT_SECRET || 'your-super-secret-jwt-key-change-in-production';
|
||||
const newToken = jwt.default.sign(
|
||||
{ userId: user.id, email: user.email },
|
||||
JWT_SECRET,
|
||||
{ expiresIn: '7d' }
|
||||
);
|
||||
|
||||
res.json({
|
||||
data: {
|
||||
user,
|
||||
token: newToken
|
||||
},
|
||||
message: 'Token刷新成功'
|
||||
});
|
||||
} catch (error) {
|
||||
next(error);
|
||||
}
|
||||
});
|
||||
|
||||
export default router;
|
||||
Reference in New Issue
Block a user