38 lines
2.3 KiB
TypeScript
38 lines
2.3 KiB
TypeScript
import { CanActivate, ExecutionContext, Inject, Injectable, UnauthorizedException } from '@nestjs/common';
|
|
import type { Database } from '@atlas/database';
|
|
import { AuthService } from '../auth/auth.service.js';
|
|
import { ApiError } from '../common/api-error.js';
|
|
import { DATABASE } from '../database/database.module.js';
|
|
|
|
export type ExtensionAuthenticatedRequest = {
|
|
header: (name: string) => string | undefined;
|
|
extensionAuth: { userId: string; workspaceId: string; sessionId: string; clientId: string };
|
|
};
|
|
|
|
@Injectable()
|
|
export class ExtensionAccessGuard implements CanActivate {
|
|
public constructor(@Inject(AuthService) private readonly auth: AuthService, @Inject(DATABASE) private readonly database: Database) {}
|
|
public async canActivate(context: ExecutionContext) {
|
|
const request = context.switchToHttp().getRequest<ExtensionAuthenticatedRequest>();
|
|
// 毛子 ERP 风格:插件携带从 Atlas Web 同步而来的短期 Web access token。
|
|
// AuthService 同时核对 JWT 和未撤销的 Web session,不能仅信任 token 声明。
|
|
let authenticated: { userId: string; sessionId: string };
|
|
try {
|
|
authenticated = await this.auth.authenticate(request.header('authorization'));
|
|
} catch (error) {
|
|
// AuthService 的通用认证守卫会抛 Nest UnauthorizedException;扩展接口
|
|
// 应返回稳定、可操作的错误信息,不能在 UI 中退化成“请求无法处理”。
|
|
if (error instanceof UnauthorizedException)
|
|
throw new ApiError(401, 'SESSION_EXPIRED', 'Atlas ERP 登录已过期,请重新登录');
|
|
throw error;
|
|
}
|
|
const workspace = await this.database.query<{ id: string }>(`SELECT w.id FROM atlas.workspace_memberships m
|
|
JOIN atlas.workspaces w ON w.id = m.workspace_id
|
|
WHERE m.user_id = $1 AND w.status = 'active'
|
|
ORDER BY m.joined_at LIMIT 1`, [authenticated.userId]);
|
|
if (!workspace.rows[0]) throw new ApiError(403, 'WORKSPACE_MEMBERSHIP_REQUIRED', '当前账户没有可用工作空间');
|
|
request.extensionAuth = { userId: authenticated.userId, workspaceId: workspace.rows[0].id, sessionId: authenticated.sessionId, clientId: 'atlas-web' };
|
|
return true;
|
|
}
|
|
}
|