feat: harden platform workflows and UI governance

This commit is contained in:
hectorzhao
2026-07-22 14:14:55 +08:00
parent ef957f7daa
commit 0f223f7f91
80 changed files with 4958 additions and 764 deletions
+16 -7
View File
@@ -1,6 +1,6 @@
import { Injectable, NestMiddleware, UnauthorizedException } from '@nestjs/common';
import { PrismaService } from '../prisma/prisma.service';
import { AuthSessionRecord, DEVELOPMENT_SESSION_COOKIE_NAME, SESSION_COOKIE_NAME, SessionService } from './session.service';
import { AuthSessionRecord, SessionPortal, SessionService } from './session.service';
export type SessionRequest = {
header(name: string): string | undefined;
@@ -22,9 +22,10 @@ export class SessionValidationMiddleware implements NestMiddleware {
return;
}
const token = this.readCookie(request.header('cookie'));
const portal = this.portalForPath(path);
const token = portal ? this.readCookie(request.header('cookie'), portal) : undefined;
if (!token) {
if ((path.includes('/admin/') && !path.includes('/admin/gateway/')) || path.includes('/client/') || path.includes('/auth/')) {
if (portal && !path.includes('/admin/gateway/')) {
throw this.unauthorized('SESSION_INVALID', '请先登录');
}
next();
@@ -43,14 +44,15 @@ export class SessionValidationMiddleware implements NestMiddleware {
await this.sessions.remove(token);
throw this.unauthorized('SESSION_REVOKED', '登录会话已被撤销,请重新登录');
}
if ((path.includes('/admin/') && result.record.portal !== 'admin') || (path.includes('/client/') && result.record.portal !== 'client')) {
if (result.record.portal !== portal) {
throw this.unauthorized('SESSION_PORTAL_MISMATCH', '登录入口与当前会话不匹配');
}
request.sessionUserId = user.id;
request.sessionToken = token;
request.authSession = result.record;
if (result.status === 'locked' && !path.includes('/auth/session/unlock') && !path.includes('/auth/logout')) {
const isSessionRecoveryRoute = /\/auth\/(?:session(?:\/unlock)?|logout)(?:\?|$)/.test(path);
if (result.status === 'locked' && !isSessionRecoveryRoute) {
if (result.newlyLocked) {
await this.prisma.operationLog.create({
data: { userId: user.id, action: 'auth.session_locked', resource: 'auth_session', detail: { portal: result.record.portal, reason: 'idle_timeout' } },
@@ -61,11 +63,18 @@ export class SessionValidationMiddleware implements NestMiddleware {
next();
}
private readCookie(cookieHeader?: string) {
private portalForPath(path: string): SessionPortal | undefined {
if (/\/admin\//.test(path)) return 'admin';
if (/\/client\//.test(path)) return 'client';
return undefined;
}
private readCookie(cookieHeader: string | undefined, portal: SessionPortal) {
if (!cookieHeader) return undefined;
const cookieName = this.sessions.cookieName(portal);
for (const part of cookieHeader.split(';')) {
const [name, ...value] = part.trim().split('=');
if (name === SESSION_COOKIE_NAME || name === DEVELOPMENT_SESSION_COOKIE_NAME) return decodeURIComponent(value.join('='));
if (name === cookieName) return decodeURIComponent(value.join('='));
}
return undefined;
}