forked from ChaiHao/BPOS-MVP
基线:鉴权会话+工作组+工作台三区修复+编排工作区+产品设计文档
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01KeDBx2PHLavbURXB8LJJ7m
This commit is contained in:
@@ -4,12 +4,14 @@
|
||||
*/
|
||||
import { Hono } from 'hono';
|
||||
import type { ApiError } from '@contracts';
|
||||
import { DEFAULT_LOGIN_ACCOUNT } from '@modules/org';
|
||||
import { healthRoute, ingestMailRoute, loginRoute } from '@contracts';
|
||||
import type { Container } from './container.ts';
|
||||
import type { AppEnv } from './http-env.ts';
|
||||
import { readSessionToken } from './session-cookie.ts';
|
||||
import { registerDeskRoutes } from './routes/desk.ts';
|
||||
import { registerDeskElementRoutes } from './routes/desk-elements.ts';
|
||||
import { registerDeskApprovalRoutes } from './routes/desk-approval.ts';
|
||||
import { registerRegistrationRoutes } from './routes/registration.ts';
|
||||
import { registerGovernanceOpsRoutes } from './routes/governance-ops.ts';
|
||||
import { registerGovernanceRoutes } from './routes/governance.ts';
|
||||
import { registerIngestRoutes } from './routes/ingest.ts';
|
||||
@@ -18,15 +20,40 @@ import { registerWorkbenchRoutes } from './routes/workbench.ts';
|
||||
|
||||
export type { AppEnv };
|
||||
|
||||
/**
|
||||
* 免鉴权白名单(ADR-010)—— 只三条,其余一律 401。
|
||||
* 入站邮件是**外界边界**:它代替真实 IMAP 拉件,不是人的请求,没有会话可言。
|
||||
*/
|
||||
const INGEST_PREFIX = ingestMailRoute.path.slice(0, ingestMailRoute.path.indexOf(':'));
|
||||
|
||||
function isPublic(method: string, path: string): boolean {
|
||||
if (method === 'GET' && path === healthRoute.path) return true;
|
||||
if (method === 'POST' && path === loginRoute.path) return true;
|
||||
if (method === 'POST' && path.startsWith(INGEST_PREFIX)) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
export function createServer(container: Container): Hono<AppEnv> {
|
||||
const app = new Hono<AppEnv>();
|
||||
|
||||
// 单组织 cookie session(编码规范 §4 鉴权定调)—— MVP 单登录者,cookie 缺省即种子登录者
|
||||
/**
|
||||
* 鉴权中间件(编码规范 §4:中间件在 app 层,身份判定读 `org` 出口;ADR-010)。
|
||||
*
|
||||
* 身份**只能**来自服务端会话表:cookie 里是一枚不透明 token,改它只会让会话解不出来,
|
||||
* 冒充不了任何人 —— 这正是明文 `jcai_account` cookie 被废止的理由。
|
||||
*/
|
||||
app.use('*', async (c, next) => {
|
||||
const cookie = c.req.header('cookie') ?? '';
|
||||
const match = /(?:^|;\s*)jcai_account=([^;]+)/.exec(cookie);
|
||||
c.set('account', match?.[1] ?? DEFAULT_LOGIN_ACCOUNT);
|
||||
const token = readSessionToken(c.req.header('cookie'));
|
||||
const session = token === undefined ? undefined : await container.org.resolveSession(token);
|
||||
c.set('session', session);
|
||||
c.set('account', session?.staff.account ?? '');
|
||||
|
||||
if (session === undefined && !isPublic(c.req.method, c.req.path)) {
|
||||
const body: ApiError = { code: 'unauthenticated', message: '尚未登录' };
|
||||
return c.json(body, 401);
|
||||
}
|
||||
await next();
|
||||
return undefined;
|
||||
});
|
||||
|
||||
app.onError((error, c) => {
|
||||
@@ -48,6 +75,7 @@ export function createServer(container: Container): Hono<AppEnv> {
|
||||
registerDeskRoutes(app, container);
|
||||
registerDeskElementRoutes(app, container);
|
||||
registerDeskApprovalRoutes(app, container);
|
||||
registerRegistrationRoutes(app, container);
|
||||
registerGovernanceOpsRoutes(app, container);
|
||||
registerIngestRoutes(app, container);
|
||||
registerStreamRoute(app, container.broadcaster);
|
||||
|
||||
Reference in New Issue
Block a user