feat: 后端用户认证和权限过滤
- 新增 auth 模块:jumpToken 代理交换、用户信息获取、JWT 签发 - 三级权限:full(所有权限/数智中心/BI-Leader)、department(BI-Leader-Dep)、personal - 添加 managerId 到车辆数据模型,支持个人级别按 userId 精确过滤 - auth 中间件保护所有 /api/* 端点(跳过 /api/health 和 /api/auth/*) - 所有路由集成 filterByPermission 权限过滤 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
37
src/server/auth/middleware.ts
Normal file
37
src/server/auth/middleware.ts
Normal file
@@ -0,0 +1,37 @@
|
||||
import type { Context, Next } from 'hono';
|
||||
import jwt from 'jsonwebtoken';
|
||||
import type { JwtPayload, AuthUser } from './types.js';
|
||||
|
||||
const JWT_SECRET = process.env.JWT_SECRET || 'ln-bi-default-secret';
|
||||
|
||||
export async function authMiddleware(c: Context, next: Next) {
|
||||
const path = c.req.path;
|
||||
|
||||
// 跳过不需要认证的路径
|
||||
if (path === '/api/health' || path.startsWith('/api/auth/')) {
|
||||
return next();
|
||||
}
|
||||
|
||||
const authHeader = c.req.header('Authorization');
|
||||
if (!authHeader?.startsWith('Bearer ')) {
|
||||
return c.json({ error: 'Unauthorized' }, 401);
|
||||
}
|
||||
|
||||
const token = authHeader.slice(7);
|
||||
|
||||
try {
|
||||
const payload = jwt.verify(token, JWT_SECRET) as JwtPayload;
|
||||
const user: AuthUser = {
|
||||
userId: payload.userId,
|
||||
userName: payload.userName,
|
||||
loginName: payload.loginName,
|
||||
depCode: payload.depCode,
|
||||
depName: payload.depName,
|
||||
permissionLevel: payload.permissionLevel,
|
||||
};
|
||||
c.set('user', user);
|
||||
return next();
|
||||
} catch {
|
||||
return c.json({ error: 'Invalid or expired token' }, 401);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user