@ dofe/sso-nestjs (英语)
雀巢JS整合 sso.dofe.ai 内部服务API.
安装
pnpm add @dofe/sso-nestjs @dofe/sso-node @nestjs/axios
使用量
import { Module } from '@nestjs/common';
import { ConfigService } from '@nestjs/config';
import { SsoClientModule } from '@dofe/sso-nestjs';
@Module({
imports: [
SsoClientModule.forRootAsync({
inject: [ConfigService],
useFactory: (config: ConfigService) => ({
baseUrl: config.getOrThrow('SSO_INTERNAL_API_URL'),
internalSecret: config.getOrThrow('INTERNAL_API_SECRET'),
serviceName: 'agents.dofe.ai',
}),
}),
],
})
export class AppModule {}
import { Injectable } from '@nestjs/common';
import { SsoClientService } from '@dofe/sso-nestjs';
@Injectable()
export class ExampleService {
constructor(private readonly sso: SsoClientService) {}
async loadUser(userId: string) {
return this.sso.getUser(userId);
}
}
对于低水平接入,使用基础 @dofe/sso-node 客户端 :
await this.sso.client.users.get(userId);
await this.sso.client.teams.getMembers(teamId);
await this.sso.client.permissions.check({ userId, teamId, permission });
对于从现有的当地SSO客户端迁移, SsoClientService 还揭露了平坦的帮助方法:
await this.sso.getUser(userId);
await this.sso.getUserTeams(userId);
await this.sso.checkPermission(userId, permission, teamId);
await this.sso.getTeamMembers(teamId);
await this.sso.getUserTeamRole(teamId, userId);
await this.sso.getTenantMembers(tenantId);
await this.sso.getUserTenantRole(tenantId, userId);
对于许可检查,更喜欢 SsoPermissionService 手写 HTTP
消费项目的客户:
import { Injectable } from '@nestjs/common';
import { SsoPermissionService } from '@dofe/sso-nestjs';
@Injectable()
export class PermissionService {
constructor(private readonly ssoPermissions: SsoPermissionService) {}
checkLoopPermission(userId: string, action: string, teamId?: string) {
return this.ssoPermissions.checkModulePermission(userId, 'vibecoding', 'loops', action, teamId);
}
}
AuthGuard 基础
消费者 AuthGuards 扩展 DofeSsoAuthGuardBase,授权标准
SSO 令牌验证 / 黑名单 / 本地用户 / 管理流向 SDK 并保存
仅在项目特定的逻辑 SsoAuthGuardHooks +一个子类.
import { Injectable } from '@nestjs/common';
import {
DofeSsoAuthGuardBase,
type SsoAuthGuardHooks,
type SsoAuthenticatedRequest,
} from '@dofe/sso-nestjs';
@Injectable()
export class MyAuthHooks implements SsoAuthGuardHooks {
async resolveLocalUser(ssoSub, claims) {
/* find/create local user */
}
resolveIsAdmin(localUser, claims) {
return localUser.isAdmin;
}
async isBlacklisted?(token) {
/* optional token blacklist */
}
async shouldBypass?(req, ctx) {
/* optional: health/internal bypass */
}
}
@Injectable()
export class AuthGuard extends DofeSsoAuthGuardBase {
/* project-specific checks only */
}
仅由 Dev 绕行(例如 .
MODE_USER_ID故意不在基地内—— 在您的子类中执行它或shouldBypass钩.
OIDC 信任党
SsoOidcRelyingPartyModule + 键 SsoOidcRelyingPartyService 拥有 PKCE
授权 / 回调 / 交换 / 刷新 / 登录流 . 生产必须
插入一个 Redis 支持的状态存储 (默认) InMemoryStateStore 输
状态为重新启动时, 不共享实例 :
import {
SsoOidcRelyingPartyModule,
OIDC_RP_STATE_STORE,
createRedisOidcStateStore,
} from '@dofe/sso-nestjs';
SsoOidcRelyingPartyModule.forRootAsync({
inject: [ConfigService, RedisService],
useFactory: (config, redis) => ({
clientId: config.getOrThrow('SSO_CLIENT_ID'),
clientSecret: config.getOrThrow('SSO_CLIENT_SECRET'),
issuerUrl: config.getOrThrow('SSO_ISSUER'),
internalIssuerUrl: config.get('SSO_INTERNAL_API_URL'),
redirectPath: '/auth/oidc/callback',
successPath: '/auth/oidc/success',
serviceName: 'agents.dofe.ai',
}),
stateStore: {
provide: OIDC_RP_STATE_STORE,
inject: [RedisService],
useFactory: (redis) => createRedisOidcStateStore(redis, { keyPrefix: 'dofe:oidc:' }),
},
});
createRedisOidcStateStore 是驱动不可知性(duck-typed ioredis表面)——
sDK 不依赖于任何再分配驱动程序; 通过您的应用程序的现有客户端 .
OIDC 帮助者(DOFE_RF_COOKIE, (中文(简体) ), classifyRefreshError, (中文(简体) ), resolveOidcUrls, (中文(简体) ),
isSecureCookieRequired, (中文(简体) ), getCookieDomain, (中文(简体) ), getDefaultCookieOptions已经
无框架,可自行导入.
边界
这个包包包 @dofe/sso-node 带有巢穴模块 HttpService 取来者. 它不包括Redis事件订阅者,Prisma,迁移,种子,或数据库连接逻辑.
固定浏览器双入口
SessionV2BffOptions.browserContexts 与 resolveBrowserContext(request) 必须同时配置。
页:1 canonical库克,金库,53
保险库
(原始内容存档于2017-03-25). id, QQ URL; 由来地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地地。
配置解析器后,登录使用 establishForRequest(request, reply, tokens, user)·
sealExchange(tokens, user, request) 3⁄4 ̄ ̧漯B redeemExchange(reply, sealed, request)
{\fn黑体\fs22\bord1\shad0\3ahbe\4ah00\fscx67\fscy66\2chffffff\3ch808080}你说什么。
publicApiPath SDK 化名。
*** 上下文 ch browserOrigin, (中文)cookieName, (中文)cookiePath 为固定服务端配置
__Host- Cookie -% 路径=/% 域名。 native QQ 靴子
bootstrapRedirectUri(92名客户;)
靴子圈 URI 由 BFF 送往 SSO, 不接受浏览器体 中的目标声明。体。
→ SID → 上下文 → 调度证明 → 上下文 {\fn黑体\fs22\bord1\shad0\3ahbe\4ah00\fscx67\fscy66\2chffffff\3ch808080}回放 转回。
可选届会时间安排
SessionV2ClientOptions.onTiming 财务报告和审定财务报表 SessionV2BffOptions.onTiming 接受
SessionV2TimingObserver, (中文(简体) ), (event: SessionV2TimingEvent) => void | Promise<void>。 。 。 .
所有时间类型均从包根导出. 钩是可选的;
同步抛出 同步拒绝 被忽略 承诺永远不会
等着呢 保持观察同步工作缩短.
活动仅包含 phase, (中文(简体) ), operation,非负数 durationMs, (中文(简体) ), outcome
(单位:千美元)success 或者说 error),和可选数字 HTTP status没有识别器,
请求对象、URL、证书或应答有效载荷被释放.
| 阶段 | 运行 | 边界 |
|---|---|---|
remote | exchange-code, (中文(简体) ), rotate, (中文(简体) ), introspect, (中文(简体) ), renew-ticket, (中文(简体) ), confirmation, (中文(简体) ), bootstrap-exchange, (中文(简体) ), logout-confirmation, (中文(简体) ), logout, (中文(简体) ), call | SSO 通过 JSON 机构解析和 HTTP 错误处理获取 . call 是其它路径的固定倒置。 呼叫后的方法级计划检查不在此限. |
active-entry | read | 故障读取,过期和撤销检查. |
admission | begin-dispatch, (中文(简体) ), begin-window-dispatch | 地铁招生,包括其远程内测和租赁收购. |
completion | complete | 破损完成承诺. |
compat-dispatch | dispatch | 通过缓冲体和完成来进行上游取水的相容性,或流接;不包括随后的流接期. |
嵌入跨度重叠:不总和录取/完成及其远程跨度.
status 是原始的 HTTP 响应状态, 即使SDK 正在使一个
错误为 503. 远程成功描述 HTTP/ JSON 完成, 不是活动
课程赠款。 兼容性 HTTP 状态 QQ 400 产生出错误结果而不包含
改变上游的反应。 直接运输仍在进行中,且未发出
相近的间隔。 兼容性响应转发保留 Server-Timing
和现有的 x-request-id; 它不注入或重写有校正条件的请求
标题或向前任意的上游标题。 未添加关联标识符
用于事件;应用程序可以使用自己的同步上下文连接事件.