352 lines
8.3 KiB
Markdown
352 lines
8.3 KiB
Markdown
# 認證與授權 API
|
||
|
||
## 📋 概述
|
||
Drama Ling 應用的認證與授權系統,支援傳統註冊登入和第三方社群登入(Apple ID、Google)。
|
||
|
||
## 🔐 JWT 認證機制
|
||
|
||
### Token 結構
|
||
```json
|
||
{
|
||
"alg": "HS256",
|
||
"typ": "JWT"
|
||
}
|
||
{
|
||
"sub": "550e8400-e29b-41d4-a716-446655440000",
|
||
"email": "user@example.com",
|
||
"username": "dramatic_learner",
|
||
"role": "user", // user, subscriber, admin
|
||
"subscription_status": "active", // active, inactive, trial
|
||
"iat": 1693920600,
|
||
"exp": 1693924200
|
||
}
|
||
```
|
||
|
||
### Token 生命週期
|
||
- **Access Token**: 1小時有效期
|
||
- **Refresh Token**: 30天有效期
|
||
- **Token 輪替**: 每次刷新會產生新的 Refresh Token
|
||
- **Token 黑名單**: 登出時將 Token 加入黑名單
|
||
|
||
## 📌 API 端點
|
||
|
||
### 1. 用戶註冊
|
||
```http
|
||
POST /api/v1/auth/register
|
||
Content-Type: application/json
|
||
|
||
{
|
||
"email": "user@example.com",
|
||
"password": "securePassword123",
|
||
"username": "dramatic_learner",
|
||
"preferredLanguage": "en",
|
||
"nativeLanguage": "zh-TW"
|
||
}
|
||
```
|
||
|
||
#### 回應範例
|
||
```http
|
||
Response 201 Created
|
||
{
|
||
"success": true,
|
||
"data": {
|
||
"userId": "550e8400-e29b-41d4-a716-446655440000",
|
||
"username": "dramatic_learner",
|
||
"email": "user@example.com",
|
||
"accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
|
||
"refreshToken": "550e8400-e29b-41d4-a716-446655440001",
|
||
"expiresIn": 3600,
|
||
"userRole": "user",
|
||
"isNewUser": true
|
||
},
|
||
"message": "User registered successfully",
|
||
"meta": {
|
||
"timestamp": "2024-09-07T12:00:00Z",
|
||
"requestId": "550e8400-e29b-41d4-a716-446655440002"
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 註冊驗證規則
|
||
- **Email**: 有效的電子郵件格式
|
||
- **Password**: 最少8位,包含大小寫字母和數字
|
||
- **Username**: 3-20字元,僅允許字母數字和底線
|
||
- **Language**: ISO 639-1 語言碼
|
||
|
||
#### 錯誤處理
|
||
```http
|
||
Response 400 Bad Request
|
||
{
|
||
"success": false,
|
||
"error": {
|
||
"code": "VALIDATION_ERROR",
|
||
"message": "註冊資料驗證失敗",
|
||
"details": {
|
||
"email": ["Email format is invalid"],
|
||
"password": ["Password must be at least 8 characters"],
|
||
"username": ["Username already exists"]
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
### 2. 用戶登入
|
||
```http
|
||
POST /api/v1/auth/login
|
||
Content-Type: application/json
|
||
|
||
{
|
||
"email": "user@example.com",
|
||
"password": "securePassword123",
|
||
"rememberMe": true
|
||
}
|
||
```
|
||
|
||
#### 回應範例
|
||
```http
|
||
Response 200 OK
|
||
{
|
||
"success": true,
|
||
"data": {
|
||
"userId": "550e8400-e29b-41d4-a716-446655440000",
|
||
"username": "dramatic_learner",
|
||
"email": "user@example.com",
|
||
"accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
|
||
"refreshToken": "550e8400-e29b-41d4-a716-446655440001",
|
||
"expiresIn": 3600,
|
||
"userRole": "subscriber",
|
||
"subscriptionStatus": "active",
|
||
"lastLoginAt": "2024-09-07T12:00:00Z"
|
||
},
|
||
"message": "Login successful"
|
||
}
|
||
```
|
||
|
||
#### 錯誤處理
|
||
```http
|
||
Response 401 Unauthorized
|
||
{
|
||
"success": false,
|
||
"error": {
|
||
"code": "INVALID_CREDENTIALS",
|
||
"message": "Email或密碼錯誤",
|
||
"details": {
|
||
"attemptCount": 3,
|
||
"lockoutTime": null
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
### 3. Token 刷新
|
||
```http
|
||
POST /api/v1/auth/refresh
|
||
Authorization: Bearer <refresh_token>
|
||
```
|
||
|
||
#### 回應範例
|
||
```http
|
||
Response 200 OK
|
||
{
|
||
"success": true,
|
||
"data": {
|
||
"accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
|
||
"refreshToken": "550e8400-e29b-41d4-a716-446655440001",
|
||
"expiresIn": 3600,
|
||
"tokenType": "Bearer"
|
||
},
|
||
"message": "Token refreshed successfully"
|
||
}
|
||
```
|
||
|
||
### 4. 用戶登出
|
||
```http
|
||
POST /api/v1/auth/logout
|
||
Authorization: Bearer <access_token>
|
||
```
|
||
|
||
#### 回應範例
|
||
```http
|
||
Response 200 OK
|
||
{
|
||
"success": true,
|
||
"data": {
|
||
"loggedOut": true,
|
||
"tokenBlacklisted": true
|
||
},
|
||
"message": "Logout successful"
|
||
}
|
||
```
|
||
|
||
### 5. Apple ID 登入
|
||
```http
|
||
POST /api/v1/auth/apple
|
||
Content-Type: application/json
|
||
|
||
{
|
||
"identityToken": "apple_identity_token",
|
||
"authorizationCode": "apple_authorization_code",
|
||
"userIdentifier": "apple_user_identifier",
|
||
"email": "user@privaterelay.appleid.com",
|
||
"fullName": {
|
||
"givenName": "John",
|
||
"familyName": "Doe"
|
||
}
|
||
}
|
||
```
|
||
|
||
#### 回應範例
|
||
```http
|
||
Response 200 OK
|
||
{
|
||
"success": true,
|
||
"data": {
|
||
"userId": "550e8400-e29b-41d4-a716-446655440000",
|
||
"username": "apple_user_12345",
|
||
"email": "user@privaterelay.appleid.com",
|
||
"accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
|
||
"refreshToken": "550e8400-e29b-41d4-a716-446655440001",
|
||
"expiresIn": 3600,
|
||
"isNewUser": false,
|
||
"authProvider": "apple"
|
||
},
|
||
"message": "Apple login successful"
|
||
}
|
||
```
|
||
|
||
### 6. Google 登入
|
||
```http
|
||
POST /api/v1/auth/google
|
||
Content-Type: application/json
|
||
|
||
{
|
||
"idToken": "google_id_token",
|
||
"accessToken": "google_access_token",
|
||
"serverAuthCode": "google_server_auth_code"
|
||
}
|
||
```
|
||
|
||
#### 回應範例
|
||
```http
|
||
Response 200 OK
|
||
{
|
||
"success": true,
|
||
"data": {
|
||
"userId": "550e8400-e29b-41d4-a716-446655440000",
|
||
"username": "google_user_12345",
|
||
"email": "user@gmail.com",
|
||
"accessToken": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...",
|
||
"refreshToken": "550e8400-e29b-41d4-a716-446655440001",
|
||
"expiresIn": 3600,
|
||
"isNewUser": true,
|
||
"authProvider": "google"
|
||
},
|
||
"message": "Google login successful"
|
||
}
|
||
```
|
||
|
||
## 🔒 權限控制
|
||
|
||
### 用戶角色
|
||
```typescript
|
||
enum UserRole {
|
||
USER = "user", // 免費用戶
|
||
SUBSCRIBER = "subscriber", // 訂閱用戶
|
||
ADMIN = "admin" // 管理員
|
||
}
|
||
```
|
||
|
||
### 權限矩陣
|
||
| 功能 | 免費用戶 | 訂閱用戶 | 管理員 |
|
||
|------|----------|----------|---------|
|
||
| 基礎對話練習 | 3次/日 | 無限制 | 無限制 |
|
||
| 高級對話功能 | ❌ | ✅ | ✅ |
|
||
| 詞彙複習 | 基礎 | 進階 | 完整 |
|
||
| 特殊任務 | 部分 | 完整 | 完整 |
|
||
| 數據分析 | 基礎 | 詳細 | 完整 |
|
||
| 管理功能 | ❌ | ❌ | ✅ |
|
||
|
||
### 權限檢查中介軟體
|
||
```javascript
|
||
// API 權限檢查範例
|
||
app.use('/api/v1/dialogues/advanced', requireSubscription);
|
||
app.use('/api/v1/admin/*', requireAdminRole);
|
||
|
||
function requireSubscription(req, res, next) {
|
||
if (req.user.role !== 'subscriber' && req.user.role !== 'admin') {
|
||
return res.status(403).json({
|
||
success: false,
|
||
error: {
|
||
code: "SUBSCRIPTION_REQUIRED",
|
||
message: "此功能需要訂閱會員"
|
||
}
|
||
});
|
||
}
|
||
next();
|
||
}
|
||
```
|
||
|
||
## ⚡ 安全措施
|
||
|
||
### 密碼安全
|
||
- **加密**: bcrypt + salt,成本因子 12
|
||
- **複雜度**: 最少8位,大小寫字母+數字
|
||
- **重設**: 臨時token,15分鐘有效期
|
||
|
||
### 防攻擊機制
|
||
- **Rate Limiting**: 每IP每分鐘5次登入嘗試
|
||
- **帳號鎖定**: 5次失敗後鎖定15分鐘
|
||
- **CSRF Protection**: 所有POST請求需要CSRF token
|
||
- **Input Sanitization**: 所有輸入進行清理和驗證
|
||
|
||
### Token 安全
|
||
- **HTTPS Only**: 所有認證相關請求強制HTTPS
|
||
- **HttpOnly Cookies**: Refresh token存放在HttpOnly cookie
|
||
- **Token 黑名單**: 登出和可疑活動時加入黑名單
|
||
- **定期輪替**: 每24小時自動輪替長期token
|
||
|
||
## 🔧 錯誤碼
|
||
|
||
### 認證相關錯誤
|
||
| 錯誤碼 | HTTP狀態 | 描述 |
|
||
|--------|----------|------|
|
||
| `INVALID_CREDENTIALS` | 401 | 登入憑證錯誤 |
|
||
| `TOKEN_EXPIRED` | 401 | Token已過期 |
|
||
| `TOKEN_INVALID` | 401 | Token無效或格式錯誤 |
|
||
| `TOKEN_BLACKLISTED` | 401 | Token已被列入黑名單 |
|
||
| `ACCOUNT_LOCKED` | 423 | 帳號因多次失敗嘗試被鎖定 |
|
||
| `EMAIL_EXISTS` | 409 | 電子郵件已被註冊 |
|
||
| `USERNAME_EXISTS` | 409 | 使用者名稱已存在 |
|
||
| `VALIDATION_ERROR` | 400 | 輸入資料驗證失敗 |
|
||
| `SOCIAL_LOGIN_ERROR` | 400 | 第三方登入驗證失敗 |
|
||
|
||
## 🧪 測試指南
|
||
|
||
### 測試用例
|
||
```bash
|
||
# 正常註冊流程測試
|
||
curl -X POST https://api.dramaling.com/api/v1/auth/register \
|
||
-H "Content-Type: application/json" \
|
||
-d '{"email":"test@example.com","password":"Test123456","username":"testuser"}'
|
||
|
||
# 登入流程測試
|
||
curl -X POST https://api.dramaling.com/api/v1/auth/login \
|
||
-H "Content-Type: application/json" \
|
||
-d '{"email":"test@example.com","password":"Test123456"}'
|
||
|
||
# Token刷新測試
|
||
curl -X POST https://api.dramaling.com/api/v1/auth/refresh \
|
||
-H "Authorization: Bearer <refresh_token>"
|
||
```
|
||
|
||
### 安全測試
|
||
- **暴力破解測試**: 驗證帳號鎖定機制
|
||
- **Token洩漏測試**: 驗證Token黑名單機制
|
||
- **權限繞過測試**: 驗證角色權限控制
|
||
- **資料注入測試**: 驗證輸入清理機制
|
||
|
||
---
|
||
|
||
**模組負責人**: 後端團隊
|
||
**最後更新**: 2024年9月7日
|
||
**相關文檔**: [用戶管理API](./user-management.md), [錯誤處理](./errors.md) |