286 lines
7.9 KiB
Markdown
286 lines
7.9 KiB
Markdown
# OIDC Provider Demo
|
||
|
||
这是一个基于 Hono 后端的 OpenID Connect (OIDC) Provider 演示应用,使用了标准的OIDC架构设计。
|
||
|
||
## 功能特性
|
||
|
||
- ✅ 完整的 OIDC Provider 实现
|
||
- ✅ 支持授权码流程 (Authorization Code Flow)
|
||
- ✅ 支持 PKCE (Proof Key for Code Exchange)
|
||
- ✅ 内置认证处理器
|
||
- ✅ JWT 令牌签发和验证
|
||
- ✅ 用户信息端点
|
||
- ✅ 令牌撤销
|
||
- ✅ Redis 存储适配器
|
||
- ✅ 内置登录页面
|
||
|
||
## 标准OIDC架构
|
||
|
||
### 使用内置认证处理器(推荐)
|
||
|
||
```typescript
|
||
import { createOIDCProvider } from '@repo/oidc-provider';
|
||
|
||
// 使用内置认证处理器,Provider自己处理登录
|
||
const oidcApp = createOIDCProvider({
|
||
config: oidcConfig,
|
||
useBuiltInAuth: true,
|
||
builtInAuthConfig: {
|
||
passwordValidator: validatePassword,
|
||
sessionTTL: 24 * 60 * 60, // 24小时
|
||
loginPageTitle: 'OIDC Demo 登录',
|
||
brandName: 'OIDC Demo Provider',
|
||
},
|
||
});
|
||
```
|
||
|
||
### 自定义认证处理器(高级用法)
|
||
|
||
```typescript
|
||
import { createOIDCProvider, type AuthHandler } from '@repo/oidc-provider';
|
||
|
||
class MyAuthHandler implements AuthHandler {
|
||
async getCurrentUser(c: Context): Promise<string | null> {
|
||
// 检查用户认证状态
|
||
// 例如:从JWT token、session或cookie中获取用户ID
|
||
const token = c.req.header('Authorization');
|
||
return await verifyTokenAndGetUserId(token);
|
||
}
|
||
|
||
async handleAuthRequired(c: Context, authRequest: AuthorizationRequest): Promise<Response> {
|
||
// 处理未认证用户
|
||
// 例如:显示自定义登录页面或重定向到外部认证服务
|
||
return this.showCustomLoginPage(c, authRequest);
|
||
}
|
||
}
|
||
|
||
const oidcApp = createOIDCProvider({
|
||
config: oidcConfig,
|
||
authHandler: new MyAuthHandler()
|
||
});
|
||
```
|
||
|
||
## 启动服务
|
||
|
||
```bash
|
||
# 在项目根目录
|
||
cd apps/backend
|
||
bun run dev
|
||
```
|
||
|
||
服务将在 `http://localhost:8000` 启动。
|
||
|
||
## 当前配置
|
||
|
||
当前的 OIDC Provider 已配置为:
|
||
- 使用内置认证处理器,Provider自己处理所有登录逻辑
|
||
- 支持标准OIDC授权码流程
|
||
- 使用 Redis 存储令牌和会话
|
||
|
||
## OIDC 端点
|
||
|
||
### 发现文档
|
||
```
|
||
GET http://localhost:8000/oidc/.well-known/openid-configuration
|
||
```
|
||
|
||
### 主要端点
|
||
- **授权端点**: `http://localhost:8000/oidc/auth`
|
||
- **令牌端点**: `http://localhost:8000/oidc/token`
|
||
- **用户信息端点**: `http://localhost:8000/oidc/userinfo`
|
||
- **JWKS端点**: `http://localhost:8000/oidc/.well-known/jwks.json`
|
||
- **撤销端点**: `http://localhost:8000/oidc/revoke`
|
||
|
||
## 测试客户端
|
||
|
||
### 机密客户端 (Confidential Client)
|
||
```
|
||
Client ID: demo-client
|
||
Client Secret: demo-client-secret
|
||
重定向URI:
|
||
- http://localhost:3000/callback
|
||
- http://localhost:8080/callback
|
||
- https://oauth.pstmn.io/v1/callback
|
||
```
|
||
|
||
### 公共客户端 (Public Client)
|
||
```
|
||
Client ID: demo-public-client
|
||
重定向URI:
|
||
- http://localhost:3000/callback
|
||
- myapp://callback
|
||
```
|
||
|
||
## 测试用户
|
||
|
||
```
|
||
用户名: demouser
|
||
密码: password
|
||
用户ID (sub): demo-user
|
||
```
|
||
|
||
## API 测试
|
||
|
||
运行测试脚本验证新API:
|
||
|
||
```bash
|
||
cd apps/backend
|
||
bun run test-oidc.ts
|
||
```
|
||
|
||
## 授权流程
|
||
|
||
1. **客户端发起授权请求**: 访问 `/oidc/auth` 端点
|
||
2. **检查用户认证**: AuthHandler 检查用户是否已认证
|
||
3. **用户认证**: 如未认证,重定向到登录页面
|
||
4. **生成授权码**: 认证成功后生成授权码
|
||
5. **交换访问令牌**: 客户端使用授权码换取访问令牌
|
||
6. **访问资源**: 使用访问令牌访问用户信息等资源
|
||
|
||
## 配置说明
|
||
|
||
```typescript
|
||
import { createOIDCProvider, DefaultAuthHandler } from '@repo/oidc-provider';
|
||
|
||
const oidcConfig = {
|
||
issuer: 'http://localhost:8000/oidc',
|
||
signingKey: 'your-secret-key',
|
||
storage: redisAdapter,
|
||
findClient: async (clientId) => { /* 查找客户端 */ },
|
||
findUser: async (userId) => { /* 查找用户 */ },
|
||
// ... 其他配置
|
||
};
|
||
|
||
// 方式1: 使用内置认证处理器(推荐)
|
||
const app1 = createOIDCProvider({
|
||
config: oidcConfig,
|
||
useBuiltInAuth: true,
|
||
builtInAuthConfig: {
|
||
passwordValidator: validatePassword,
|
||
sessionTTL: 24 * 60 * 60,
|
||
loginPageTitle: 'OIDC Demo 登录',
|
||
brandName: 'OIDC Demo Provider',
|
||
},
|
||
});
|
||
|
||
// 方式2: 使用自定义处理器(高级用法)
|
||
const app2 = createOIDCProvider({
|
||
config: oidcConfig,
|
||
authHandler: new CustomAuthHandler()
|
||
});
|
||
```
|
||
|
||
## 与 Next.js Web 应用集成
|
||
|
||
1. **标准OIDC流程**: Next.js 应用使用标准 oidc-client-ts 库
|
||
2. **认证处理**: OIDC Provider 自己处理所有用户认证和登录页面
|
||
3. **令牌管理**: OIDC Provider 负责生成和管理所有令牌
|
||
4. **回调处理**: Next.js 应用只需处理OIDC回调,获取令牌
|
||
|
||
## 技术架构
|
||
|
||
- **框架**: Hono.js
|
||
- **存储**: Redis (令牌存储)
|
||
- **JWT**: JOSE 库
|
||
- **PKCE**: 支持 SHA256 和 plain 方法
|
||
- **算法**: HS256 (可配置 RS256, ES256)
|
||
- **认证**: 可自定义认证处理器
|
||
|
||
## 优势
|
||
|
||
相比之前的实现,新API具有以下优势:
|
||
|
||
1. **简化配置**: 只需要提供配置对象和认证处理器
|
||
2. **灵活认证**: 支持任意认证方式(JWT、Session、OAuth等)
|
||
3. **清晰分离**: 认证逻辑与OIDC协议逻辑分离
|
||
4. **易于扩展**: 通过实现 AuthHandler 接口轻松自定义
|
||
5. **类型安全**: 完整的 TypeScript 类型支持
|
||
|
||
## 开发说明
|
||
|
||
- 修改客户端或用户数据:编辑 `src/oidc-demo.ts`
|
||
- 自定义认证逻辑:实现 `AuthHandler` 接口
|
||
- 配置调整:修改 `oidcConfig` 对象
|
||
|
||
## 快速测试
|
||
|
||
1. **Web界面测试**:
|
||
访问 http://localhost:8000 查看完整的测试界面
|
||
|
||
2. **授权流程测试**:
|
||
访问 http://localhost:8000/oidc/auth?response_type=code&client_id=demo-client&redirect_uri=https://oauth.pstmn.io/v1/callback&scope=openid%20profile%20email&state=test-state
|
||
|
||
3. **Postman测试**:
|
||
使用以下配置在 Postman 中测试 OAuth 2.0:
|
||
```
|
||
授权URL: http://localhost:8000/oidc/auth
|
||
令牌URL: http://localhost:8000/oidc/token
|
||
回调URL: https://oauth.pstmn.io/v1/callback
|
||
Client ID: demo-client
|
||
Client Secret: demo-client-secret
|
||
作用域: openid profile email
|
||
```
|
||
|
||
## 完整的授权码流程
|
||
|
||
### 1. 授权请求
|
||
```
|
||
GET http://localhost:8000/oidc/auth?response_type=code&client_id=demo-client&redirect_uri=https://oauth.pstmn.io/v1/callback&scope=openid%20profile%20email&state=random-state
|
||
```
|
||
|
||
### 2. 用户登录
|
||
系统会自动重定向到登录页面,使用测试用户登录
|
||
|
||
### 3. 获取授权码
|
||
登录成功后会重定向到 `redirect_uri` 并携带授权码
|
||
|
||
### 4. 交换访问令牌
|
||
```bash
|
||
curl -X POST http://localhost:8000/oidc/token \
|
||
-H "Content-Type: application/x-www-form-urlencoded" \
|
||
-d "grant_type=authorization_code&code=YOUR_CODE&redirect_uri=https://oauth.pstmn.io/v1/callback&client_id=demo-client&client_secret=demo-client-secret"
|
||
```
|
||
|
||
### 5. 访问用户信息
|
||
```bash
|
||
curl -X GET http://localhost:8000/oidc/userinfo \
|
||
-H "Authorization: Bearer YOUR_ACCESS_TOKEN"
|
||
```
|
||
|
||
## 支持的作用域和声明
|
||
|
||
### 作用域 (Scopes)
|
||
- `openid` - 必需的基础作用域
|
||
- `profile` - 用户基本信息
|
||
- `email` - 邮箱信息
|
||
- `phone` - 电话号码
|
||
- `address` - 地址信息
|
||
|
||
### 声明 (Claims)
|
||
- `sub` - 用户唯一标识
|
||
- `name`, `given_name`, `family_name` - 姓名信息
|
||
- `email`, `email_verified` - 邮箱信息
|
||
- `phone_number`, `phone_number_verified` - 电话信息
|
||
- `picture`, `profile`, `website` - 个人资料
|
||
- `gender`, `birthdate`, `zoneinfo`, `locale` - 基本信息
|
||
- `address` - 地址信息
|
||
- `updated_at` - 更新时间
|
||
|
||
## 安全注意事项
|
||
|
||
⚠️ **这是一个演示应用,不应用于生产环境!**
|
||
|
||
生产环境部署时需要注意:
|
||
1. 使用强密钥和安全的签名算法
|
||
2. 实现真实的用户认证和会话管理
|
||
3. 添加适当的安全头和 CSRF 保护
|
||
4. 使用 HTTPS
|
||
5. 实现客户端注册和管理
|
||
6. 添加速率限制和监控
|
||
7. 定期轮换密钥
|
||
|
||
## 开发和扩展
|
||
|
||
如需修改客户端或用户数据,编辑 `src/oidc-demo.ts` 文件中的 `demoClients` 和 `demoUsers` 数组。
|
||
|
||
如需自定义认证逻辑,修改 `src/index.ts` 中的登录处理逻辑。 |