oauth_nest_demo/OAuth-JWT-Integration.md

173 lines
4.2 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# OAuth JWT 集成实现文档
## 🎯 实现目标
将飞书和 GitHub 的第三方 OAuth access_token 转换为项目自己的 JWT Token实现统一的认证体系。
## 🏗️ 架构设计
### 用户数据模型扩展
扩展了 `User` 实体以支持多种登录方式:
```typescript
@Entity()
export class User {
@PrimaryGeneratedColumn()
id: number;
@Column({ unique: true })
username: string;
@Column({ nullable: true }) // OAuth 用户不需要密码
password: string;
@Column()
email: string;
@Column({ default: true })
isActive: boolean;
// OAuth 相关字段
@Column({ nullable: true })
provider: string; // 'local', 'github', 'lark'
@Column({ nullable: true })
providerId: string; // 第三方平台的用户ID
@Column({ nullable: true })
providerUsername: string; // 第三方平台的用户名
// JWT 相关字段
@Column({ nullable: true })
refreshToken: string;
@Column({ nullable: true })
refreshTokenExpires: Date;
}
```
### UserService 扩展
添加了 OAuth 用户专用的方法:
1. **`findUserByProvider(provider, providerId)`** - 根据第三方平台信息查找用户
2. **`createOAuthUser(provider, providerId, providerUsername, email)`** - 创建 OAuth 用户
### 用户名生成策略
为避免用户名冲突OAuth 用户的用户名格式为:
- 格式:`{provider}_{providerUsername}`
- 示例:`github_octocat`, `lark_zhangsan`
- 如果冲突,自动添加数字后缀:`github_octocat_1`
## 🔄 OAuth 流程
### GitHub OAuth 流程
1. **登录入口**`GET /github/login?redirectUri=<回调地址>`
2. **OAuth 回调**`GET /github/callback?code=<授权码>`
3. **处理流程**
```
授权码 → GitHub Access Token → 用户信息 → 查找/创建本地用户 → 生成 JWT Token
```
### 飞书 OAuth 流程
1. **登录入口**`GET /lark/login?redirectUri=<回调地址>`
2. **OAuth 回调**`GET /lark/callback?code=<授权码>`
3. **处理流程**
```
授权码 → 飞书 Access Token → 用户信息 → 查找/创建本地用户 → 生成 JWT Token
```
## 📝 API 响应格式
### 成功响应
```json
{
"message": "GitHub login successful",
"user": {
"id": 1,
"username": "github_octocat",
"email": "octocat@github.com",
"provider": "github",
"providerUsername": "octocat"
},
"access_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"refresh_token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
"expires_in": 3600,
"expires_at": 1703123456789,
"refresh_token_expires_in": 604800,
"refresh_token_expires_at": 1703728256789
}
```
## 🛡️ 安全特性
1. **用户隔离** - OAuth 用户和本地用户完全分离
2. **唯一标识** - 使用 `provider + providerId` 作为唯一标识
3. **JWT 安全** - 使用项目统一的 JWT 密钥和过期策略
4. **缓存机制** - 第三方 token 和用户信息缓存,减少 API 调用
## 🔧 配置要求
### 环境变量
```env
# GitHub OAuth
GITHUB_CLIENT_ID=your_github_client_id
GITHUB_CLIENT_SECRET=your_github_client_secret
GITHUB_CALLBACK_URL=http://localhost:3030/auth/github/callback
# 飞书 OAuth
FEISHU_APP_ID=your_feishu_app_id
FEISHU_APP_SECRET=your_feishu_app_secret
# JWT
JWT_SECRET=your_jwt_secret
```
## 🧪 测试
访问测试页面:`http://localhost:8000/test-github-sso.html`
支持的登录方式:
- GitHub OAuth
- 飞书 OAuth
- Passport GitHub 策略(用于重定向场景)
## 🚀 使用示例
### 前端调用
```javascript
// GitHub 登录
window.location.href = 'http://localhost:3030/github/login?redirectUri=' +
encodeURIComponent(window.location.origin + '/callback');
// 飞书登录
window.location.href = 'http://localhost:3030/lark/login?redirectUri=' +
encodeURIComponent(window.location.origin + '/callback');
```
### 使用 JWT Token
```javascript
// 在后续请求中使用 JWT Token
fetch('/api/protected', {
headers: {
'Authorization': `Bearer ${access_token}`
}
});
```
## 📋 优势
1. **统一认证** - 所有用户最终都使用项目的 JWT Token
2. **类型安全** - 完整的 TypeScript 类型定义
3. **扩展性强** - 易于添加新的 OAuth 提供商
4. **数据一致性** - 统一的用户数据模型
5. **安全可靠** - 遵循 OAuth 2.0 和 JWT 最佳实践