feat: newapi-dashboard 全栈项目初始化
为 new-api (LLM API 网关) 构建独立前端管理面板: - React 18 + TypeScript + Vite + Ant Design 5 前端 - Node.js + Express + better-sqlite3 BFF 后端 - 登录页: 站点选择器 + UserID + AccessToken 认证 - 仪表盘: 用户信息、额度环形图、7天趋势图、模型饼图、令牌概览、日志时间线 - 账单页: 筛选日志表格、模型消耗柱状图、充值记录、CSV/PDF 导出(HMAC签名) - 管理员站点管理: 站点 CRUD - API 代理: 多站点切换,会话管理 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
51
server/middleware/auth.ts
Normal file
51
server/middleware/auth.ts
Normal file
@@ -0,0 +1,51 @@
|
||||
import { Request, Response, NextFunction } from 'express'
|
||||
import db from '../db.js'
|
||||
|
||||
export interface SessionData {
|
||||
id: string
|
||||
user_id: number
|
||||
access_token: string
|
||||
site_id: number
|
||||
site_url: string
|
||||
user_info: string
|
||||
}
|
||||
|
||||
declare global {
|
||||
namespace Express {
|
||||
interface Request {
|
||||
session?: SessionData
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export function sessionAuth(req: Request, res: Response, next: NextFunction) {
|
||||
const token = req.headers['x-session-token'] as string
|
||||
if (!token) {
|
||||
res.status(401).json({ success: false, message: '未登录' })
|
||||
return
|
||||
}
|
||||
|
||||
const session = db.prepare(
|
||||
"SELECT * FROM sessions WHERE id = ? AND expires_at > datetime('now')"
|
||||
).get(token) as SessionData | undefined
|
||||
|
||||
if (!session) {
|
||||
res.status(401).json({ success: false, message: '会话已过期,请重新登录' })
|
||||
return
|
||||
}
|
||||
|
||||
req.session = session
|
||||
next()
|
||||
}
|
||||
|
||||
export function adminAuth(req: Request, res: Response, next: NextFunction) {
|
||||
sessionAuth(req, res, () => {
|
||||
if (!req.session) return
|
||||
const userInfo = JSON.parse(req.session.user_info || '{}')
|
||||
if (userInfo.role < 10) {
|
||||
res.status(403).json({ success: false, message: '需要管理员权限' })
|
||||
return
|
||||
}
|
||||
next()
|
||||
})
|
||||
}
|
||||
Reference in New Issue
Block a user