docs: 更新 OIDC Provider 文档并完善环境配置
文档更新: - 从"实施方案"改为"实施文档",标记为已完成状态 - 添加快速开始章节,提供完整的使用示例 - 补充第一方应用自动授权的两种场景实现细节 - 补充 Grant Scope 存储的 payload 结构说明 - 新增客户端服务章节(cuid2 ID + 随机密钥) - 更新关键文件清单(后端/前端/共享类型) 环境配置: - 添加 FRONTEND_URL 配置 - 添加 OIDC Provider 开发环境配置 Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
@@ -8,6 +8,7 @@ JWT_EXPIRES_IN="7d"
|
|||||||
|
|
||||||
PORT=4000
|
PORT=4000
|
||||||
NODE_ENV=development
|
NODE_ENV=development
|
||||||
|
FRONTEND_URL=http://localhost:3000
|
||||||
|
|
||||||
# ----- 加密配置 -----
|
# ----- 加密配置 -----
|
||||||
# 是否启用通信加密
|
# 是否启用通信加密
|
||||||
@@ -38,3 +39,8 @@ MINIO_ACCESS_KEY=minioadmin
|
|||||||
MINIO_SECRET_KEY=minioadmin
|
MINIO_SECRET_KEY=minioadmin
|
||||||
MINIO_BUCKET=seclusion
|
MINIO_BUCKET=seclusion
|
||||||
MINIO_PUBLIC_URL=
|
MINIO_PUBLIC_URL=
|
||||||
|
|
||||||
|
# ----- OIDC Provider 配置 -----
|
||||||
|
OIDC_ISSUER=http://localhost:4000/oidc
|
||||||
|
OIDC_COOKIE_SECRET=oidc-cookie-secret-change-in-production
|
||||||
|
OIDC_JWKS_PRIVATE_KEY=LS0tLS1CRUdJTiBQUklWQVRFIEtFWS0tLS0tCk1JSUV2UUlCQURBTkJna3Foa2lHOXcwQkFRRUZBQVNDQktjd2dnU2pBZ0VBQW9JQkFRRFhGYkJ5cDVKc2Y1UWsKS213UnhObkxOMHE2Rzk1djZjQ1ZENW5EZmpzeDE0cDZpS2NRaG5jZU9JMmF2bDdGUUJGZzcyN1QvMlFqRExYegpHd05rcUhpcmo0ZlNHeERzN2x3c1RqSkRNUE51akF0NnlIMVVMdDBrWUxJL2pwRlhUUWNKdTFKQlc5OWZwTnU1CitoQkZpMHd4cnljQmRpWjlEeVg2K0I2YjhzRDRlRzdZbXJOSzlhd3NuQjVmQTUxUG4rWHRrNUM1YktvRjI4N0sKb1owRGxPZU1jY003S0I4elc4L1ZyZnE4Mk9pNDd3T3ZScmIwQ2I5aG5Ia0dUQWhyT0xzNjE5R1oyM1FnZzg1cQpVL2FXMGZwSG56WHpETWV5ak5scXJoRlgvb1hQak5EaHMvUGE2MHozZWxtS1dOZ1ByQ0dtb08ySnd6NDlmZkVFCjBDU2xNTzZiQWdNQkFBRUNnZ0VBRmQzL3BYaUIrNFB4Qk1oSFduc2dCWGdtb2N0Smp5azl5aW5lNFRCSlJtVDYKa0VDcWM1U29NYXRnUWpaT25sRklNd25FdzhyNFhGUGpmOGJrVG15T2NDclVqVGp4UEpWelM1SGJyRmNpdUwrRwpQMEo0ODRFY1BLR1VIY0FaNkwxTkZPRTFtSzJGaFV6V2hnNzFib3lkLzRNbVBSRE5FdlBpVWFTK1ArNnJUZGVJCi9UbVdwTnVic25ockJ0RE1pSDZ2RDBSMEJBK1NzTkI2Nkw5elI2UUVqSXhCOW12aGpJaXJyR3hkREprcVRldFEKRnVZZUNMVVpSMXVYU1dYdXFzSWZQSmNpbjJtblVpdUhFa3Z0bUVlaG9mL1g1ZVJNYWsvTmc0UmtUWHF5Y2FudwpDN3NOdUFmai9rNU51QTlWazJVVi9qanVmUWowSktKb2drQUhWVGRtMlFLQmdRRHVZZGpkeXNkSjlkTXJJN3BFCnRZNTJPaU0vaWkyQ2dsanZvTXZFejljTEFiOEVNbVpiRlUrTmhWRUVVbDBkK3dJYTNmUFFBKzRVZ2t6U09oUHcKT1E1NVk0SUp5Rm9yOFdLZ0hBcUI4ZHo3dnlTZWVSNmZUM1R5TFdSN3RJKzV6ZVZEQU1pNFEwUnRKRDFMeFVzMApBQnlzK0lIc2hmYUd2N1NxN1lUMytsMkZGd0tCZ1FEbSt3NnVhTVhsTUVtUW9remVFTWYwTGNwVHMxcTJPN3ZtCk9XSFB5TTNnTlY5UWVIUUF1dC9mNmU1VWVPdnliWHg5SjAxcEU3Z29RdWRhRWpiSkl4eXgyWXlaYkVzS28rV3kKR05mWk9RL1F5YWxHL29PYXFxQUpPdFVGa0dvUzlOaDV1R0Y1eXY5YmRQRU9TeTN0dVhpNzVxNE9sQ3RYVnM1WApBbWtMTVd6ZEhRS0JnQllsM3lsVU1zbnJYaEJQQkhwbngvR3lHeDVITDAxRjRROTZpQlFrSDEyMWJ0THIvOWlNCmxWU1h3MXc4YnN4ZlN1WEdJMlg3UjM1K1VMYmprSUNzUEcwSTBzY241MERYNzRyaXNCTThyb1J4VU95c1lpejUKQyt1SVRpSzBOdnBUWis2ZXZ3ZG5zSTdYWkI2TEdSNmV1QXRXRjNRclNpbGczRjlaTEJhQ0czaEhBb0dBR3VRegp5MTVyVzhtSlp3dGVRNlJVZ3pzcGlTRWllSUR2MlZmbzZWWUprZ2JrdCt1dUpiK2IvT2V4VmFoV1gvMGJOejd5CkpqK2pleHgrN3QrYi9VTFhQbVdEbHdFaW8zUjljNFNzN0o5V0ZnckVhSDJOT042UWowS0lOb09mdGVGSHFyUXEKdFJGTE5ZeWgyL1lvdkxxUk1kOGplSk1Ma0xtTWdGakpmZ0lkR0lrQ2dZRUFoL3BMRlVnNFNueGRxWm51bG13cQpVaEgvcVY0ck9zY1hRVkJidHArOTNSWVJ6THQ2c0VRT2NNWExLVGtEcU5UZzBLamdub2wyM2NJbnVSSWNRcE9rClcvTUlqZEsrZnEvaXJUZnJ4bzM3cUhRNXo4cFdtOWY3L29TeHIvS1RlaWFTYkFrZ0ptSVdQeCt5bnhvQmZHV00Kcnp5dmlvUjV4Uk10YTBCaS8rTkxtM0U9Ci0tLS0tRU5EIFBSSVZBVEUgS0VZLS0tLS0K
|
||||||
|
|||||||
@@ -1,11 +1,90 @@
|
|||||||
# OIDC Provider 实施方案
|
# OIDC Provider 实施文档
|
||||||
|
|
||||||
本文档描述如何将系统扩展为 OIDC Provider,对外提供中央鉴权业务。
|
本文档描述系统作为 OIDC Provider 对外提供中央鉴权业务的实现方案。
|
||||||
|
|
||||||
|
> **实施状态**:✅ 已完成(2025年1月)
|
||||||
|
|
||||||
## 一、方案概述
|
## 一、方案概述
|
||||||
|
|
||||||
基于 [panva/node-oidc-provider](https://github.com/panva/node-oidc-provider) 库实现 OIDC Provider 功能,该库是 OpenID Certified 的成熟实现,支持完整的 OAuth 2.0 和 OpenID Connect 规范。
|
基于 [panva/node-oidc-provider](https://github.com/panva/node-oidc-provider) 库实现 OIDC Provider 功能,该库是 OpenID Certified 的成熟实现,支持完整的 OAuth 2.0 和 OpenID Connect 规范。
|
||||||
|
|
||||||
|
### 1.1 核心特性
|
||||||
|
|
||||||
|
- **混合存储策略**:PostgreSQL 存储持久化数据,Redis 存储短期/会话数据
|
||||||
|
- **第一方应用自动授权**:配置 `isFirstParty: true` 的客户端自动跳过授权确认页
|
||||||
|
- **完整的客户端管理**:支持创建、编辑、删除客户端,以及密钥重新生成
|
||||||
|
- **标准 OIDC 端点**:支持授权、令牌、用户信息、JWKS、令牌撤销等标准端点
|
||||||
|
|
||||||
|
### 1.2 快速开始
|
||||||
|
|
||||||
|
**1. 环境配置**
|
||||||
|
|
||||||
|
确保 `.env` 文件包含以下配置:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
OIDC_ISSUER=http://localhost:4000/oidc
|
||||||
|
OIDC_COOKIE_SECRET=your-oidc-cookie-secret
|
||||||
|
OIDC_JWKS_PRIVATE_KEY=<Base64编码的RSA私钥>
|
||||||
|
```
|
||||||
|
|
||||||
|
生成 JWKS 私钥:
|
||||||
|
```bash
|
||||||
|
openssl genrsa 2048 | base64 -w 0
|
||||||
|
```
|
||||||
|
|
||||||
|
**2. 创建客户端**
|
||||||
|
|
||||||
|
通过管理界面(/oidc-clients)或 API 创建 OIDC 客户端:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -X POST http://localhost:4000/oidc-clients \
|
||||||
|
-H "Authorization: Bearer <token>" \
|
||||||
|
-H "Content-Type: application/json" \
|
||||||
|
-d '{
|
||||||
|
"clientName": "我的应用",
|
||||||
|
"redirectUris": ["http://localhost:3001/callback"],
|
||||||
|
"grantTypes": ["authorization_code", "refresh_token"],
|
||||||
|
"scopes": ["openid", "profile", "email"],
|
||||||
|
"isFirstParty": false
|
||||||
|
}'
|
||||||
|
```
|
||||||
|
|
||||||
|
响应会包含 `clientId` 和 `clientSecret`(仅显示一次)。
|
||||||
|
|
||||||
|
**3. 发起授权**
|
||||||
|
|
||||||
|
引导用户访问授权端点:
|
||||||
|
|
||||||
|
```
|
||||||
|
http://localhost:4000/oidc/authorize
|
||||||
|
?client_id=<clientId>
|
||||||
|
&redirect_uri=http://localhost:3001/callback
|
||||||
|
&response_type=code
|
||||||
|
&scope=openid profile email
|
||||||
|
&state=<random_state>
|
||||||
|
```
|
||||||
|
|
||||||
|
**4. 获取令牌**
|
||||||
|
|
||||||
|
用户授权后,使用授权码换取令牌:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl -X POST http://localhost:4000/oidc/token \
|
||||||
|
-u "<clientId>:<clientSecret>" \
|
||||||
|
-d "grant_type=authorization_code" \
|
||||||
|
-d "code=<authorization_code>" \
|
||||||
|
-d "redirect_uri=http://localhost:3001/callback"
|
||||||
|
```
|
||||||
|
|
||||||
|
**5. 获取用户信息**
|
||||||
|
|
||||||
|
使用 Access Token 获取用户信息:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
curl http://localhost:4000/oidc/userinfo \
|
||||||
|
-H "Authorization: Bearer <access_token>"
|
||||||
|
```
|
||||||
|
|
||||||
## 二、数据存储设计
|
## 二、数据存储设计
|
||||||
|
|
||||||
### 2.1 存储策略
|
### 2.1 存储策略
|
||||||
@@ -131,21 +210,21 @@ model User {
|
|||||||
```
|
```
|
||||||
apps/api/src/oidc/
|
apps/api/src/oidc/
|
||||||
├── oidc.module.ts # OIDC 模块定义
|
├── oidc.module.ts # OIDC 模块定义
|
||||||
├── oidc.controller.ts # OIDC 端点控制器
|
├── oidc.controller.ts # 交互端点控制器(/oidc-interaction)
|
||||||
├── oidc.service.ts # OIDC 核心服务
|
├── oidc.service.ts # OIDC 核心服务(Provider 初始化与管理)
|
||||||
├── adapters/
|
├── adapters/
|
||||||
|
│ ├── index.ts # 混合适配器工厂
|
||||||
│ ├── prisma.adapter.ts # Prisma 存储适配器(Client、Grant、RefreshToken)
|
│ ├── prisma.adapter.ts # Prisma 存储适配器(Client、Grant、RefreshToken)
|
||||||
│ └── redis.adapter.ts # Redis 存储适配器(AuthorizationCode、AccessToken、Session、Interaction)
|
│ └── redis.adapter.ts # Redis 存储适配器(AuthorizationCode、AccessToken、Session、Interaction)
|
||||||
|
├── controllers/
|
||||||
|
│ └── client.controller.ts # 客户端管理控制器(/oidc-clients)
|
||||||
├── services/
|
├── services/
|
||||||
│ ├── account.service.ts # 账户查找服务
|
│ ├── account.service.ts # 账户查找服务(findAccount 实现)
|
||||||
│ ├── client.service.ts # 客户端管理服务
|
│ ├── client.service.ts # 客户端管理服务(CRUD + 密钥生成)
|
||||||
│ └── interaction.service.ts # 交互处理服务
|
│ └── interaction.service.ts # 交互处理服务(登录、授权确认)
|
||||||
├── dto/
|
├── dto/
|
||||||
│ ├── client.dto.ts # 客户端 DTO
|
│ ├── client.dto.ts # 客户端 DTO(创建、更新、响应)
|
||||||
│ ├── consent.dto.ts # 授权确认 DTO
|
│ └── interaction.dto.ts # 交互 DTO(登录、授权确认)
|
||||||
│ └── interaction.dto.ts # 交互 DTO
|
|
||||||
├── guards/
|
|
||||||
│ └── oidc-interaction.guard.ts # 交互会话守卫
|
|
||||||
└── config/
|
└── config/
|
||||||
└── oidc.config.ts # OIDC Provider 配置
|
└── oidc.config.ts # OIDC Provider 配置
|
||||||
```
|
```
|
||||||
@@ -326,7 +405,41 @@ export class OidcAccountService {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
#### 3.2.5 OIDC 配置 (`config/oidc.config.ts`)
|
#### 3.2.5 客户端服务 (`services/client.service.ts`)
|
||||||
|
|
||||||
|
客户端 ID 使用 cuid2 生成,客户端密钥使用 64 字符随机十六进制:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
import { randomBytes } from 'crypto';
|
||||||
|
import { Injectable } from '@nestjs/common';
|
||||||
|
import { createId } from '@paralleldrive/cuid2';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class OidcClientService extends CrudService<...> {
|
||||||
|
// 生成客户端 ID(使用 cuid2,格式如 clxxx...)
|
||||||
|
private generateClientId(): string {
|
||||||
|
return createId();
|
||||||
|
}
|
||||||
|
|
||||||
|
// 生成客户端密钥(64 字符随机十六进制,无前缀)
|
||||||
|
private generateClientSecret(): string {
|
||||||
|
return randomBytes(32).toString('hex');
|
||||||
|
}
|
||||||
|
|
||||||
|
async createClient(dto: CreateOidcClientDto) {
|
||||||
|
const clientId = this.generateClientId();
|
||||||
|
const clientSecret = this.generateClientSecret();
|
||||||
|
// ...创建客户端逻辑
|
||||||
|
}
|
||||||
|
|
||||||
|
async regenerateSecret(id: string) {
|
||||||
|
const clientSecret = this.generateClientSecret();
|
||||||
|
// ...更新密钥逻辑
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
#### 3.2.6 OIDC 配置 (`config/oidc.config.ts`)
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
import type { Configuration } from 'oidc-provider';
|
import type { Configuration } from 'oidc-provider';
|
||||||
@@ -408,7 +521,7 @@ export function createOidcConfiguration(
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
#### 3.2.6 OIDC 控制器 (`oidc.controller.ts`)
|
#### 3.2.7 OIDC 控制器 (`oidc.controller.ts`)
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
import { All, Controller, Get, Post, Req, Res, UseGuards } from '@nestjs/common';
|
import { All, Controller, Get, Post, Req, Res, UseGuards } from '@nestjs/common';
|
||||||
@@ -467,7 +580,7 @@ export class OidcController {
|
|||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
#### 3.2.7 客户端管理控制器 (`client.controller.ts`)
|
#### 3.2.8 客户端管理控制器 (`client.controller.ts`)
|
||||||
|
|
||||||
```typescript
|
```typescript
|
||||||
@ApiTags('OIDC 客户端管理')
|
@ApiTags('OIDC 客户端管理')
|
||||||
@@ -909,7 +1022,7 @@ OIDC_JWKS_PRIVATE_KEY=
|
|||||||
- 支持 private_key_jwt 高安全认证方式
|
- 支持 private_key_jwt 高安全认证方式
|
||||||
4. **授权确认**:
|
4. **授权确认**:
|
||||||
- 第三方应用必须经过用户授权确认
|
- 第三方应用必须经过用户授权确认
|
||||||
- 第一方应用可配置跳过确认
|
- **第一方应用自动授权**(见下文详细说明)
|
||||||
- 记住用户授权决定,避免重复确认
|
- 记住用户授权决定,避免重复确认
|
||||||
5. **令牌撤销**:
|
5. **令牌撤销**:
|
||||||
- 支持主动撤销 Access Token 和 Refresh Token
|
- 支持主动撤销 Access Token 和 Refresh Token
|
||||||
@@ -918,34 +1031,138 @@ OIDC_JWKS_PRIVATE_KEY=
|
|||||||
- Token 端点需要支持跨域请求
|
- Token 端点需要支持跨域请求
|
||||||
- 配置允许的 Origin 列表
|
- 配置允许的 Origin 列表
|
||||||
|
|
||||||
|
### 8.1 第一方应用自动授权实现
|
||||||
|
|
||||||
|
第一方应用(`isFirstParty: true`)在两种场景下自动跳过授权确认页:
|
||||||
|
|
||||||
|
**场景 1:登录时自动授权**
|
||||||
|
|
||||||
|
用户在 OIDC 登录页面输入凭据后,`finishLogin` 方法检测第一方应用并自动完成授权:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// interaction.service.ts
|
||||||
|
async finishLogin(provider, ctx, accountId, options) {
|
||||||
|
// 检查是否为第一方应用
|
||||||
|
const client = await provider.Client.find(options.clientId);
|
||||||
|
const isFirstParty = client?.['urn:custom:first_party'];
|
||||||
|
|
||||||
|
if (isFirstParty) {
|
||||||
|
// 第一方应用:登录后自动完成授权
|
||||||
|
const grant = new provider.Grant({ accountId, clientId: options.clientId });
|
||||||
|
options.scopes.forEach(scope => grant.addOIDCScope(scope));
|
||||||
|
const grantId = await grant.save();
|
||||||
|
|
||||||
|
return provider.interactionFinished(ctx.req, ctx.res, {
|
||||||
|
login: { accountId },
|
||||||
|
consent: { grantId },
|
||||||
|
}, { mergeWithLastSubmission: true });
|
||||||
|
}
|
||||||
|
|
||||||
|
// 第三方应用:仅完成登录,等待授权确认
|
||||||
|
return provider.interactionFinished(ctx.req, ctx.res, {
|
||||||
|
login: { accountId },
|
||||||
|
}, { mergeWithLastSubmission: false });
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**场景 2:已登录用户访问时自动授权**
|
||||||
|
|
||||||
|
用户已在系统登录,访问第一方应用的授权 URL 时,`getInteraction` 接口检测并自动完成授权:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// oidc.controller.ts
|
||||||
|
async getInteraction(req, res, uid) {
|
||||||
|
const details = await this.oidcService.interactionDetails(req, res);
|
||||||
|
const client = await provider.Client.find(details.params.client_id);
|
||||||
|
|
||||||
|
// 检查:consent prompt + 已登录 + 第一方应用
|
||||||
|
if (
|
||||||
|
details.prompt.name === 'consent' &&
|
||||||
|
details.session?.accountId &&
|
||||||
|
client?.['urn:custom:first_party']
|
||||||
|
) {
|
||||||
|
const scopes = details.params.scope.split(' ');
|
||||||
|
const redirectTo = await this.interactionService.finishConsent(...);
|
||||||
|
|
||||||
|
// 返回自动授权标记,前端直接重定向
|
||||||
|
return res.json({ autoConsent: true, redirectTo });
|
||||||
|
}
|
||||||
|
|
||||||
|
// 返回交互详情,前端渲染登录或授权页面
|
||||||
|
return res.json({ uid, prompt, params, client, session });
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**前端处理自动授权**:
|
||||||
|
|
||||||
|
```tsx
|
||||||
|
// page.tsx
|
||||||
|
const details = await getInteractionDetails(uid);
|
||||||
|
|
||||||
|
// 第一方应用自动授权,直接重定向
|
||||||
|
if (details.autoConsent && details.redirectTo) {
|
||||||
|
redirect(details.redirectTo);
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### 8.2 Grant Scope 存储
|
||||||
|
|
||||||
|
oidc-provider 的 Grant payload 中,scope 存储在嵌套结构中:
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
// prisma.adapter.ts - Grant 模型存储逻辑
|
||||||
|
case 'Grant': {
|
||||||
|
// payload 结构: { openid: { scope: "openid profile email" } }
|
||||||
|
const openid = payload.openid as { scope?: string } | undefined;
|
||||||
|
const scopeString = openid?.scope || '';
|
||||||
|
|
||||||
|
await this.prisma.oidcGrant.upsert({
|
||||||
|
where: { grantId: id },
|
||||||
|
update: { data: payload, scope: scopeString, expiresAt },
|
||||||
|
create: {
|
||||||
|
grantId: id,
|
||||||
|
clientId: payload.clientId,
|
||||||
|
userId: payload.accountId,
|
||||||
|
scope: scopeString,
|
||||||
|
data: payload,
|
||||||
|
expiresAt,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
## 九、实施步骤
|
## 九、实施步骤
|
||||||
|
|
||||||
### 阶段一:基础设施(1-2天)
|
> **状态**:全部阶段已完成 ✅
|
||||||
|
|
||||||
1. 添加 Prisma 数据模型
|
### 阶段一:基础设施 ✅
|
||||||
2. 实现 Prisma 适配器
|
|
||||||
3. 配置 oidc-provider
|
|
||||||
4. 集成到 NestJS 应用
|
|
||||||
|
|
||||||
### 阶段二:核心功能(2-3天)
|
1. ✅ 添加 Prisma 数据模型(OidcClient、OidcGrant、OidcRefreshToken)
|
||||||
|
2. ✅ 实现混合适配器(Prisma + Redis)
|
||||||
|
3. ✅ 配置 oidc-provider
|
||||||
|
4. ✅ 集成到 NestJS 应用(Express 中间件挂载)
|
||||||
|
|
||||||
1. 实现账户服务
|
### 阶段二:核心功能 ✅
|
||||||
2. 实现交互处理(登录、授权确认)
|
|
||||||
3. 实现客户端管理 CRUD
|
|
||||||
4. 添加权限控制
|
|
||||||
|
|
||||||
### 阶段三:前端页面(1-2天)
|
1. ✅ 实现账户服务(findAccount)
|
||||||
|
2. ✅ 实现交互处理(登录、授权确认、中止)
|
||||||
|
3. ✅ 实现客户端管理 CRUD
|
||||||
|
4. ✅ 添加权限控制(oidc-client:read/create/update/delete)
|
||||||
|
5. ✅ 实现第一方应用自动授权
|
||||||
|
|
||||||
1. 授权确认页面
|
### 阶段三:前端页面 ✅
|
||||||
2. OIDC 客户端管理页面
|
|
||||||
3. 用户已授权应用管理
|
|
||||||
|
|
||||||
### 阶段四:测试与文档(1天)
|
1. ✅ OIDC 登录页面(独立于现有登录系统)
|
||||||
|
2. ✅ 授权确认页面(scope 选择)
|
||||||
|
3. ✅ OIDC 客户端管理页面(表格 + 创建/编辑弹窗)
|
||||||
|
4. ✅ 客户端密钥重新生成功能
|
||||||
|
|
||||||
1. 单元测试
|
### 阶段四:测试与完善 ✅
|
||||||
2. 集成测试
|
|
||||||
3. API 文档完善
|
1. ✅ 端到端授权流程测试
|
||||||
4. 使用文档
|
2. ✅ 第一方应用自动授权测试
|
||||||
|
3. ✅ API 文档完善(Swagger)
|
||||||
|
4. ✅ 实施文档更新
|
||||||
|
|
||||||
## 十、NestJS 集成要点
|
## 十、NestJS 集成要点
|
||||||
|
|
||||||
@@ -1025,15 +1242,48 @@ oidc-provider 中间件挂载在 `/oidc` 路径下,会先执行。自定义交
|
|||||||
|
|
||||||
## 十一、关键文件清单
|
## 十一、关键文件清单
|
||||||
|
|
||||||
|
### 后端文件
|
||||||
|
|
||||||
| 文件 | 说明 |
|
| 文件 | 说明 |
|
||||||
|------|------|
|
|------|------|
|
||||||
| `apps/api/src/main.ts` | 应用入口,挂载 oidc-provider 中间件 |
|
| `apps/api/src/main.ts` | 应用入口,挂载 oidc-provider 中间件 |
|
||||||
| `apps/api/prisma/schema.prisma` | 添加 OIDC 相关数据模型 |
|
| `apps/api/prisma/schema.prisma` | OIDC 数据模型(OidcClient、OidcGrant、OidcRefreshToken) |
|
||||||
| `apps/api/src/oidc/` | OIDC 模块目录 |
|
| `apps/api/src/oidc/oidc.module.ts` | OIDC 模块定义 |
|
||||||
| `apps/api/src/auth/auth.service.ts` | 参考现有认证逻辑 |
|
| `apps/api/src/oidc/oidc.service.ts` | Provider 初始化与管理 |
|
||||||
| `apps/web/src/app/(oidc)/` | OIDC 交互页面(登录、授权确认) |
|
| `apps/api/src/oidc/oidc.controller.ts` | 交互端点(获取详情、登录、授权、中止) |
|
||||||
| `apps/web/src/app/(dashboard)/oidc-clients/` | OIDC 客户端管理页面 |
|
| `apps/api/src/oidc/adapters/index.ts` | 混合适配器工厂 |
|
||||||
|
| `apps/api/src/oidc/adapters/prisma.adapter.ts` | PostgreSQL 存储适配器 |
|
||||||
|
| `apps/api/src/oidc/adapters/redis.adapter.ts` | Redis 存储适配器 |
|
||||||
|
| `apps/api/src/oidc/services/account.service.ts` | 账户查找服务 |
|
||||||
|
| `apps/api/src/oidc/services/client.service.ts` | 客户端管理(cuid2 ID + 随机密钥) |
|
||||||
|
| `apps/api/src/oidc/services/interaction.service.ts` | 交互处理(含第一方自动授权) |
|
||||||
|
| `apps/api/src/oidc/controllers/client.controller.ts` | 客户端管理 API |
|
||||||
|
| `apps/api/src/oidc/config/oidc.config.ts` | OIDC Provider 配置 |
|
||||||
|
| `apps/api/src/oidc/dto/client.dto.ts` | 客户端 DTO |
|
||||||
|
| `apps/api/src/oidc/dto/interaction.dto.ts` | 交互 DTO |
|
||||||
|
|
||||||
|
### 前端文件
|
||||||
|
|
||||||
|
| 文件 | 说明 |
|
||||||
|
|------|------|
|
||||||
|
| `apps/web/src/app/(oidc)/layout.tsx` | OIDC 专用布局 |
|
||||||
|
| `apps/web/src/app/(oidc)/oidc/interaction/[uid]/page.tsx` | 交互页面(SSR) |
|
||||||
|
| `apps/web/src/app/(oidc)/oidc/interaction/[uid]/OidcLoginForm.tsx` | 登录表单 |
|
||||||
|
| `apps/web/src/app/(oidc)/oidc/interaction/[uid]/OidcConsentForm.tsx` | 授权确认表单 |
|
||||||
|
| `apps/web/src/app/(oidc)/oidc/error/page.tsx` | OIDC 错误页面 |
|
||||||
|
| `apps/web/src/app/(dashboard)/oidc-clients/page.tsx` | 客户端管理页面 |
|
||||||
|
| `apps/web/src/components/oidc-clients/OidcClientsTable.tsx` | 客户端列表表格 |
|
||||||
|
| `apps/web/src/components/oidc-clients/OidcClientCreateDialog.tsx` | 创建客户端弹窗 |
|
||||||
|
| `apps/web/src/components/oidc-clients/OidcClientEditDialog.tsx` | 编辑客户端弹窗 |
|
||||||
|
| `apps/web/src/hooks/useOidcClients.ts` | 客户端管理 hooks |
|
||||||
|
| `apps/web/src/services/oidc-client.service.ts` | 客户端 API 服务 |
|
||||||
|
|
||||||
|
### 共享类型
|
||||||
|
|
||||||
|
| 文件 | 说明 |
|
||||||
|
|------|------|
|
||||||
| `packages/shared/src/types/oidc.ts` | OIDC 共享类型定义 |
|
| `packages/shared/src/types/oidc.ts` | OIDC 共享类型定义 |
|
||||||
|
| `packages/shared/src/types/index.ts` | 类型导出(包含 OIDC 类型) |
|
||||||
|
|
||||||
## 十二、参考资料
|
## 十二、参考资料
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user