feat(auth): 添加认证模块和图片批注功能(项目初始化)
- 实现用户登录、登出、密码修改等认证功能 - 添加会话管理和权限控制中间件 - 创建图片批注组件和相关API路由 - 实现批注的增删改查功能 - 添加Docker和Git忽略配置文件 - 创建系统架构文档和开发约定说明 - 集成认证模块到前端应用路由中
This commit is contained in:
43
api/routes/auth.ts
Normal file
43
api/routes/auth.ts
Normal file
@@ -0,0 +1,43 @@
|
||||
import { Router, type Request, type Response } from 'express';
|
||||
import { database } from '../database.js';
|
||||
import { clearSession, createSession, hashPassword, sessionCookie, type AuthRequest, verifyPassword } from '../auth.js';
|
||||
|
||||
const router = Router();
|
||||
|
||||
router.post('/login', async (req: Request, res: Response) => {
|
||||
const username = String(req.body?.username ?? '').trim();
|
||||
const password = String(req.body?.password ?? '');
|
||||
const row = await database.one<{ id: number; password_hash: string }>('SELECT id, password_hash FROM users WHERE username = ? AND status = ?', [username, 'active']);
|
||||
if (!row || !verifyPassword(password, row.password_hash)) { res.status(401).json({ error: '账号或密码错误' }); return; }
|
||||
await database.execute('UPDATE users SET last_login_at = ? WHERE id = ?', [new Date().toISOString(), row.id]);
|
||||
const token = await createSession(row.id);
|
||||
res.setHeader('Set-Cookie', sessionCookie(token));
|
||||
res.json({ success: true });
|
||||
});
|
||||
|
||||
router.post('/logout', async (req: Request, res: Response) => {
|
||||
const token = req.headers.cookie?.match(/(?:^|; )proofing_session=([^;]+)/)?.[1];
|
||||
await clearSession(token);
|
||||
res.setHeader('Set-Cookie', 'proofing_session=; HttpOnly; SameSite=Lax; Path=/; Max-Age=0');
|
||||
res.status(204).end();
|
||||
});
|
||||
|
||||
router.get('/me', (req: AuthRequest, res: Response) => {
|
||||
if (!req.authUser) { res.status(401).json({ error: '未登录' }); return; }
|
||||
res.json(req.authUser);
|
||||
});
|
||||
|
||||
router.post('/change-password', async (req: AuthRequest, res: Response) => {
|
||||
if (!req.authUser) { res.status(401).json({ error: '未登录' }); return; }
|
||||
const currentPassword = String(req.body?.currentPassword ?? '');
|
||||
const newPassword = String(req.body?.newPassword ?? '');
|
||||
if (newPassword.length < 8 || !/[A-Za-z]/.test(newPassword) || !/\d/.test(newPassword)) {
|
||||
res.status(400).json({ error: '新密码至少 8 位,并同时包含字母和数字' }); return;
|
||||
}
|
||||
const row = await database.one<{ password_hash: string }>('SELECT password_hash FROM users WHERE id = ?', [req.authUser.id]);
|
||||
if (!row || !verifyPassword(currentPassword, row.password_hash)) { res.status(400).json({ error: '当前密码错误' }); return; }
|
||||
await database.execute('UPDATE users SET password_hash = ?, must_change_password = ? WHERE id = ?', [hashPassword(newPassword), false, req.authUser.id]);
|
||||
res.json({ success: true });
|
||||
});
|
||||
|
||||
export default router;
|
||||
Reference in New Issue
Block a user