729 lines
17 KiB
Markdown
729 lines
17 KiB
Markdown
# Permission Module
|
||
|
||
一個完整的 Go 權限管理模組,提供 JWT 令牌管理、RBAC(基於角色的訪問控制)以及權限樹管理功能。
|
||
|
||
## 📋 目錄
|
||
|
||
- [功能特性](#功能特性)
|
||
- [架構設計](#架構設計)
|
||
- [目錄結構](#目錄結構)
|
||
- [快速開始](#快速開始)
|
||
- [API 文檔](#api-文檔)
|
||
- [配置說明](#配置說明)
|
||
- [測試](#測試)
|
||
- [最佳實踐](#最佳實踐)
|
||
|
||
## 🎯 功能特性
|
||
|
||
### 1. JWT 令牌管理
|
||
- ✅ Access Token 與 Refresh Token 機制
|
||
- ✅ One-Time Token 支持(一次性令牌)
|
||
- ✅ 設備追蹤與管理
|
||
- ✅ 令牌黑名單機制
|
||
- ✅ 多設備登錄限制
|
||
- ✅ 令牌自動過期與刷新
|
||
|
||
### 2. RBAC 權限控制
|
||
- ✅ 層級式權限結構(權限樹)
|
||
- ✅ 角色與權限關聯管理
|
||
- ✅ 使用者與角色關聯管理
|
||
- ✅ 動態權限檢查
|
||
- ✅ HTTP API 權限映射
|
||
- ✅ 權限繼承(父權限自動包含)
|
||
|
||
### 3. 資料持久化
|
||
- ✅ Redis 令牌存儲與快取
|
||
- ✅ MongoDB 權限/角色數據存儲
|
||
- ✅ 批量查詢優化(避免 N+1)
|
||
- ✅ 軟刪除支持
|
||
|
||
### 4. 安全特性
|
||
- ✅ JWT 簽名驗證
|
||
- ✅ 令牌黑名單
|
||
- ✅ 設備指紋追蹤
|
||
- ✅ 循環依賴檢測
|
||
- ✅ 管理員權限特殊處理
|
||
|
||
## 🏗️ 架構設計
|
||
|
||
本模組遵循 **Clean Architecture** 設計原則:
|
||
|
||
```
|
||
pkg/permission/
|
||
├── domain/ # 領域層(核心業務邏輯)
|
||
│ ├── entity/ # 實體定義
|
||
│ ├── repository/ # Repository 介面
|
||
│ ├── usecase/ # UseCase 介面
|
||
│ ├── config/ # 配置定義
|
||
│ ├── permission/ # 權限類型定義
|
||
│ └── token/ # 令牌類型定義
|
||
├── usecase/ # UseCase 實現層
|
||
│ ├── token.go # 令牌業務邏輯
|
||
│ ├── permission_usecase.go # 權限業務邏輯
|
||
│ ├── role_usecase.go # 角色業務邏輯
|
||
│ ├── role_permission_usecase.go # 角色權限業務邏輯
|
||
│ ├── user_role_usecase.go # 使用者角色業務邏輯
|
||
│ └── permission_tree.go # 權限樹結構
|
||
├── repository/ # Repository 實現層(數據訪問)
|
||
│ ├── token_model.go # Redis 令牌存儲
|
||
│ ├── permission.go # MongoDB 權限存儲
|
||
│ ├── role.go # MongoDB 角色存儲
|
||
│ ├── role_permission.go # MongoDB 角色權限存儲
|
||
│ └── user_role.go # MongoDB 使用者角色存儲
|
||
└── mock/ # Mock 實現(測試用)
|
||
```
|
||
|
||
### 依賴關係圖
|
||
|
||
```
|
||
┌─────────────────┐
|
||
│ HTTP Handler │
|
||
└────────┬────────┘
|
||
│
|
||
▼
|
||
┌─────────────────┐
|
||
│ UseCase │ ◄─── 業務邏輯層
|
||
│ - Token │
|
||
│ - Permission │
|
||
│ - Role │
|
||
│ - UserRole │
|
||
└────────┬────────┘
|
||
│
|
||
▼
|
||
┌─────────────────┐
|
||
│ Repository │ ◄─── 數據訪問層
|
||
│ - Redis │
|
||
│ - MongoDB │
|
||
└────────┬────────┘
|
||
│
|
||
▼
|
||
┌─────────────────┐
|
||
│ Storage │ ◄─── 存儲層
|
||
│ - Redis │
|
||
│ - MongoDB │
|
||
└─────────────────┘
|
||
```
|
||
|
||
## 📁 目錄結構
|
||
|
||
### domain/ - 領域層
|
||
|
||
#### entity/ - 實體定義
|
||
- `token.go` - 令牌實體(Token, Ticket, Blacklist)
|
||
- `permission.go` - 權限實體
|
||
- `role.go` - 角色實體
|
||
- `role_permission.go` - 角色權限關聯實體
|
||
- `user_role.go` - 使用者角色實體
|
||
|
||
#### repository/ - Repository 介面
|
||
定義數據訪問接口,與具體實現解耦
|
||
|
||
#### usecase/ - UseCase 介面
|
||
定義業務邏輯接口,規範業務操作
|
||
|
||
#### config/ - 配置定義
|
||
- `config.go` - 模組配置結構
|
||
- `errors.go` - 配置錯誤定義
|
||
|
||
#### permission/ - 權限類型
|
||
- `types.go` - 權限狀態、類型、集合定義
|
||
|
||
#### token/ - 令牌類型
|
||
- `token_type.go` - 令牌類型常量
|
||
- `grant_type.go` - 授權類型定義
|
||
|
||
### usecase/ - 業務邏輯實現
|
||
|
||
#### 令牌管理
|
||
- `token.go` - JWT 令牌生成、驗證、刷新
|
||
- `token_jwt.go` - JWT 編解碼
|
||
- `token_claims.go` - JWT Claims 處理
|
||
|
||
#### RBAC 管理
|
||
- `permission_usecase.go` - 權限管理
|
||
- `role_usecase.go` - 角色管理
|
||
- `role_permission_usecase.go` - 角色權限管理
|
||
- `user_role_usecase.go` - 使用者角色管理
|
||
- `permission_tree.go` - 權限樹結構與操作
|
||
|
||
### repository/ - 數據訪問實現
|
||
|
||
- `token_model.go` - Redis 令牌存儲實現
|
||
- `permission.go` - MongoDB 權限存儲實現
|
||
- `role.go` - MongoDB 角色存儲實現
|
||
- `role_permission.go` - MongoDB 角色權限存儲實現
|
||
- `user_role.go` - MongoDB 使用者角色存儲實現
|
||
|
||
### mock/ - Mock 實現
|
||
|
||
自動生成的 Mock 實現,用於單元測試
|
||
|
||
## 🚀 快速開始
|
||
|
||
### 1. 安裝依賴
|
||
|
||
```bash
|
||
go get backend/pkg/permission
|
||
```
|
||
|
||
### 2. 配置
|
||
|
||
```go
|
||
import (
|
||
"backend/pkg/permission/domain/config"
|
||
"backend/pkg/permission/usecase"
|
||
"backend/pkg/permission/repository"
|
||
)
|
||
|
||
// 配置
|
||
cfg := &config.Config{
|
||
Token: config.TokenConfig{
|
||
Secret: "your-secret-key",
|
||
Expired: config.ExpiredConfig{
|
||
Seconds: 900, // 15 分鐘
|
||
},
|
||
RefreshExpires: config.ExpiredConfig{
|
||
Seconds: 604800, // 7 天
|
||
},
|
||
Issuer: "playone-backend",
|
||
MaxTokensPerUser: 10,
|
||
MaxTokensPerDevice: 5,
|
||
},
|
||
Role: config.RoleConfig{
|
||
AdminRoleUID: "ADMIN",
|
||
UIDPrefix: "ROLE",
|
||
UIDLength: 10,
|
||
},
|
||
}
|
||
```
|
||
|
||
### 3. 初始化 Repository
|
||
|
||
```go
|
||
// Redis 令牌存儲
|
||
redisClient := redis.NewClient(&redis.Options{
|
||
Addr: "localhost:6379",
|
||
})
|
||
|
||
tokenRepo := repository.NewTokenRepository(repository.TokenRepositoryParam{
|
||
Redis: redisClient,
|
||
})
|
||
|
||
// MongoDB 存儲
|
||
mongoConf := &mongo.Conf{
|
||
Host: "localhost:27017",
|
||
Database: "permission",
|
||
User: "admin",
|
||
Password: "password",
|
||
}
|
||
|
||
permRepo := repository.NewPermissionRepository(repository.PermissionRepositoryParam{
|
||
Conf: mongoConf,
|
||
CacheConf: cache.CacheConf{},
|
||
})
|
||
|
||
roleRepo := repository.NewRoleRepository(repository.RoleRepositoryParam{
|
||
Conf: mongoConf,
|
||
CacheConf: cache.CacheConf{},
|
||
})
|
||
|
||
rolePermRepo := repository.NewRolePermissionRepository(repository.RolePermissionRepositoryParam{
|
||
Conf: mongoConf,
|
||
CacheConf: cache.CacheConf{},
|
||
})
|
||
|
||
userRoleRepo := repository.NewUserRoleRepository(repository.UserRoleRepositoryParam{
|
||
Conf: mongoConf,
|
||
CacheConf: cache.CacheConf{},
|
||
})
|
||
```
|
||
|
||
### 4. 初始化 UseCase
|
||
|
||
```go
|
||
// 權限 UseCase
|
||
permUC := usecase.NewPermissionUseCase(usecase.PermissionUseCaseParam{
|
||
PermRepo: permRepo,
|
||
RolePermRepo: rolePermRepo,
|
||
RoleRepo: roleRepo,
|
||
UserRoleRepo: userRoleRepo,
|
||
})
|
||
|
||
// 角色權限 UseCase
|
||
rolePermUC := usecase.NewRolePermissionUseCase(usecase.RolePermissionUseCaseParam{
|
||
PermRepo: permRepo,
|
||
RolePermRepo: rolePermRepo,
|
||
RoleRepo: roleRepo,
|
||
UserRoleRepo: userRoleRepo,
|
||
PermUseCase: permUC,
|
||
AdminRoleUID: cfg.Role.AdminRoleUID,
|
||
})
|
||
|
||
// 角色 UseCase
|
||
roleUC := usecase.NewRoleUseCase(usecase.RoleUseCaseParam{
|
||
RoleRepo: roleRepo,
|
||
UserRoleRepo: userRoleRepo,
|
||
RolePermUseCase: rolePermUC,
|
||
Config: usecase.RoleUseCaseConfig{
|
||
AdminRoleUID: cfg.Role.AdminRoleUID,
|
||
UIDPrefix: cfg.Role.UIDPrefix,
|
||
UIDLength: cfg.Role.UIDLength,
|
||
},
|
||
})
|
||
|
||
// 使用者角色 UseCase
|
||
userRoleUC := usecase.NewUserRoleUseCase(usecase.UserRoleUseCaseParam{
|
||
UserRoleRepo: userRoleRepo,
|
||
RoleRepo: roleRepo,
|
||
})
|
||
|
||
// 令牌 UseCase
|
||
tokenUC := usecase.NewTokenUseCase(usecase.TokenUseCaseParam{
|
||
TokenRepo: tokenRepo,
|
||
Config: cfg,
|
||
})
|
||
```
|
||
|
||
## 📚 API 文檔
|
||
|
||
### 令牌管理 API
|
||
|
||
#### 生成令牌
|
||
```go
|
||
req := entity.AuthorizationReq{
|
||
GrantType: token.PasswordCredentials.ToString(),
|
||
Data: map[string]string{
|
||
"uid": "user123",
|
||
"role": "admin",
|
||
},
|
||
DeviceID: "device123",
|
||
}
|
||
|
||
tokenResp, err := tokenUC.NewToken(ctx, req)
|
||
// tokenResp.AccessToken
|
||
// tokenResp.RefreshToken
|
||
// tokenResp.ExpiresIn
|
||
```
|
||
|
||
#### 刷新令牌
|
||
```go
|
||
req := entity.RefreshTokenReq{
|
||
RefreshToken: "old-refresh-token",
|
||
DeviceID: "device123",
|
||
}
|
||
|
||
tokenResp, err := tokenUC.RefreshToken(ctx, req)
|
||
```
|
||
|
||
#### 驗證令牌
|
||
```go
|
||
isValid := tokenUC.IsAccessTokenValid(ctx, accessToken)
|
||
```
|
||
|
||
#### 取消令牌
|
||
```go
|
||
err := tokenUC.CancelToken(ctx, tokenID)
|
||
```
|
||
|
||
#### 黑名單令牌
|
||
```go
|
||
err := tokenUC.BlacklistToken(ctx, entity.BlacklistTokenReq{
|
||
TokenID: tokenID,
|
||
Reason: "User logout",
|
||
})
|
||
```
|
||
|
||
### 權限管理 API
|
||
|
||
#### 獲取所有權限
|
||
```go
|
||
permissions, err := permUC.GetAll(ctx)
|
||
```
|
||
|
||
#### 獲取權限樹
|
||
```go
|
||
tree, err := permUC.GetTree(ctx)
|
||
```
|
||
|
||
#### 根據 HTTP 路徑獲取權限
|
||
```go
|
||
perm, err := permUC.GetByHTTP(ctx, "/api/users", "GET")
|
||
```
|
||
|
||
#### 展開權限(包含父權限)
|
||
```go
|
||
perms := permission.Permissions{
|
||
"user.list": permission.Open,
|
||
}
|
||
expanded, err := permUC.ExpandPermissions(ctx, perms)
|
||
// expanded 將包含 "user" 和 "user.list"
|
||
```
|
||
|
||
### 角色管理 API
|
||
|
||
#### 創建角色
|
||
```go
|
||
req := usecase.CreateRoleRequest{
|
||
ClientID: 1,
|
||
Name: "管理員",
|
||
Permissions: permission.Permissions{
|
||
"user.list": permission.Open,
|
||
"user.create": permission.Open,
|
||
},
|
||
}
|
||
|
||
role, err := roleUC.Create(ctx, req)
|
||
```
|
||
|
||
#### 更新角色
|
||
```go
|
||
name := "高級管理員"
|
||
req := usecase.UpdateRoleRequest{
|
||
Name: &name,
|
||
Permissions: permission.Permissions{
|
||
"user.list": permission.Open,
|
||
"user.create": permission.Open,
|
||
"user.delete": permission.Open,
|
||
},
|
||
}
|
||
|
||
role, err := roleUC.Update(ctx, "ROLE0000000001", req)
|
||
```
|
||
|
||
#### 刪除角色
|
||
```go
|
||
err := roleUC.Delete(ctx, "ROLE0000000001")
|
||
```
|
||
|
||
#### 分頁查詢角色
|
||
```go
|
||
filter := usecase.RoleFilterRequest{
|
||
ClientID: 1,
|
||
Name: "管理",
|
||
}
|
||
|
||
page, err := roleUC.Page(ctx, filter, 1, 10)
|
||
// page.List - 角色列表(含使用者數量)
|
||
// page.Total - 總數
|
||
```
|
||
|
||
### 角色權限管理 API
|
||
|
||
#### 獲取角色權限
|
||
```go
|
||
perms, err := rolePermUC.GetByRoleUID(ctx, "ROLE0000000001")
|
||
```
|
||
|
||
#### 獲取使用者權限
|
||
```go
|
||
userPerms, err := rolePermUC.GetByUserUID(ctx, "user123")
|
||
// userPerms.RoleUID
|
||
// userPerms.RoleName
|
||
// userPerms.Permissions
|
||
```
|
||
|
||
#### 更新角色權限
|
||
```go
|
||
perms := permission.Permissions{
|
||
"user.list": permission.Open,
|
||
"user.create": permission.Open,
|
||
}
|
||
|
||
err := rolePermUC.UpdateRolePermissions(ctx, "ROLE0000000001", perms)
|
||
```
|
||
|
||
#### 檢查權限
|
||
```go
|
||
result, err := rolePermUC.CheckPermission(ctx, "ROLE0000000001", "/api/users", "GET")
|
||
// result.Allowed - 是否允許
|
||
// result.PermissionName - 權限名稱
|
||
// result.PlainCode - 是否有 plain_code 權限
|
||
```
|
||
|
||
### 使用者角色管理 API
|
||
|
||
#### 指派角色給使用者
|
||
```go
|
||
req := usecase.AssignRoleRequest{
|
||
UserUID: "user123",
|
||
RoleUID: "ROLE0000000001",
|
||
Brand: "brand1",
|
||
}
|
||
|
||
userRole, err := userRoleUC.Assign(ctx, req)
|
||
```
|
||
|
||
#### 更新使用者角色
|
||
```go
|
||
userRole, err := userRoleUC.Update(ctx, "user123", "ROLE0000000002")
|
||
```
|
||
|
||
#### 移除使用者角色
|
||
```go
|
||
err := userRoleUC.Remove(ctx, "user123")
|
||
```
|
||
|
||
#### 獲取角色的所有使用者
|
||
```go
|
||
userRoles, err := userRoleUC.GetByRole(ctx, "ROLE0000000001")
|
||
```
|
||
|
||
## ⚙️ 配置說明
|
||
|
||
### Token 配置
|
||
```yaml
|
||
token:
|
||
secret: "your-jwt-secret-key" # JWT 簽名密鑰
|
||
expired:
|
||
seconds: 900 # Access Token 過期時間(秒)
|
||
refresh_expires:
|
||
seconds: 604800 # Refresh Token 過期時間(秒)
|
||
issuer: "playone-backend" # 發行者
|
||
max_tokens_per_user: 10 # 每個使用者最大令牌數
|
||
max_tokens_per_device: 5 # 每個設備最大令牌數
|
||
enable_device_tracking: true # 是否啟用設備追蹤
|
||
```
|
||
|
||
### Role 配置
|
||
```yaml
|
||
role:
|
||
admin_role_uid: "ADMIN" # 管理員角色 UID
|
||
uid_prefix: "ROLE" # 角色 UID 前綴
|
||
uid_length: 10 # UID 數字長度
|
||
```
|
||
|
||
### RBAC 配置
|
||
```yaml
|
||
rbac:
|
||
enable_cache: true # 是否啟用快取
|
||
cache_ttl: 3600 # 快取過期時間(秒)
|
||
```
|
||
|
||
## 🧪 測試
|
||
|
||
### 運行所有測試
|
||
```bash
|
||
go test ./pkg/permission/... -v
|
||
```
|
||
|
||
### 運行特定測試
|
||
```bash
|
||
# 令牌測試
|
||
go test ./pkg/permission/usecase -run TestToken -v
|
||
|
||
# 權限樹測試
|
||
go test ./pkg/permission/usecase -run TestPermissionTree -v
|
||
|
||
# Repository 測試
|
||
go test ./pkg/permission/repository -v
|
||
```
|
||
|
||
### 測試覆蓋率
|
||
```bash
|
||
go test ./pkg/permission/... -cover
|
||
```
|
||
|
||
### 生成覆蓋率報告
|
||
```bash
|
||
go test ./pkg/permission/... -coverprofile=coverage.out
|
||
go tool cover -html=coverage.out -o coverage.html
|
||
```
|
||
|
||
## 💡 最佳實踐
|
||
|
||
### 1. 令牌管理
|
||
|
||
#### ✅ 推薦做法
|
||
```go
|
||
// 使用 Refresh Token 自動刷新
|
||
if tokenUC.IsAccessTokenValid(ctx, accessToken) {
|
||
// 使用令牌
|
||
} else {
|
||
// 嘗試刷新
|
||
newToken, err := tokenUC.RefreshToken(ctx, refreshReq)
|
||
if err != nil {
|
||
// 要求重新登錄
|
||
}
|
||
}
|
||
```
|
||
|
||
#### ❌ 避免做法
|
||
```go
|
||
// 不要在每次請求都生成新令牌
|
||
// 不要將令牌存儲在不安全的地方
|
||
// 不要在客戶端解析 Refresh Token
|
||
```
|
||
|
||
### 2. 權限檢查
|
||
|
||
#### ✅ 推薦做法
|
||
```go
|
||
// 使用權限檢查中間件
|
||
func AuthMiddleware(rolePermUC usecase.RolePermissionUseCase) gin.HandlerFunc {
|
||
return func(c *gin.Context) {
|
||
roleUID := c.GetString("role_uid")
|
||
result, err := rolePermUC.CheckPermission(
|
||
c.Request.Context(),
|
||
roleUID,
|
||
c.Request.URL.Path,
|
||
c.Request.Method,
|
||
)
|
||
|
||
if err != nil || !result.Allowed {
|
||
c.AbortWithStatus(http.StatusForbidden)
|
||
return
|
||
}
|
||
|
||
c.Next()
|
||
}
|
||
}
|
||
```
|
||
|
||
#### ❌ 避免做法
|
||
```go
|
||
// 不要在每個 Handler 中重複權限檢查代碼
|
||
// 不要硬編碼權限名稱
|
||
// 不要跳過權限檢查
|
||
```
|
||
|
||
### 3. 權限設計
|
||
|
||
#### ✅ 推薦做法
|
||
```go
|
||
// 使用層級式權限結構
|
||
// 例如:
|
||
// - user
|
||
// - user.list
|
||
// - user.create
|
||
// - user.update
|
||
// - user.delete
|
||
|
||
// 父權限會自動包含,只需設置子權限即可
|
||
perms := permission.Permissions{
|
||
"user.list": permission.Open,
|
||
}
|
||
// 展開後會自動包含 "user"
|
||
```
|
||
|
||
#### ❌ 避免做法
|
||
```go
|
||
// 不要創建過深的權限層級(建議 ≤ 3 層)
|
||
// 不要使用過於細緻的權限粒度
|
||
// 不要創建循環依賴的權限
|
||
```
|
||
|
||
### 4. 角色管理
|
||
|
||
#### ✅ 推薦做法
|
||
```go
|
||
// 使用預定義角色
|
||
const (
|
||
RoleAdmin = "ADMIN"
|
||
RoleManager = "MANAGER"
|
||
RoleEmployee = "EMPLOYEE"
|
||
)
|
||
|
||
// 定期檢查無使用者的角色
|
||
roles, _ := roleUC.Page(ctx, filter, 1, 100)
|
||
for _, role := range roles.List {
|
||
if role.UserCount == 0 {
|
||
// 考慮刪除或停用
|
||
}
|
||
}
|
||
```
|
||
|
||
#### ❌ 避免做法
|
||
```go
|
||
// 不要創建過多的角色
|
||
// 不要刪除有使用者的角色
|
||
// 不要頻繁修改角色權限
|
||
```
|
||
|
||
## 🔐 安全建議
|
||
|
||
1. **JWT 密鑰管理**
|
||
- 使用強密鑰(至少 32 字元)
|
||
- 定期輪換密鑰
|
||
- 不要將密鑰硬編碼在代碼中
|
||
|
||
2. **令牌過期設置**
|
||
- Access Token: 15 分鐘 - 1 小時
|
||
- Refresh Token: 7 - 30 天
|
||
- One-Time Token: 5 - 10 分鐘
|
||
|
||
3. **設備追蹤**
|
||
- 啟用設備指紋追蹤
|
||
- 限制每個設備的令牌數量
|
||
- 檢測異常登錄行為
|
||
|
||
4. **權限檢查**
|
||
- 在所有 API 端點進行權限檢查
|
||
- 使用白名單而非黑名單
|
||
- 記錄權限拒絕事件
|
||
|
||
## 📝 資料庫設計
|
||
|
||
### MongoDB Collections
|
||
|
||
#### permissions
|
||
```json
|
||
{
|
||
"_id": ObjectId,
|
||
"parent_id": ObjectId,
|
||
"name": "user.list",
|
||
"http_method": "GET",
|
||
"http_path": "/api/users",
|
||
"status": 1,
|
||
"type": 1,
|
||
"create_time": 1234567890,
|
||
"update_time": 1234567890
|
||
}
|
||
```
|
||
|
||
#### roles
|
||
```json
|
||
{
|
||
"_id": ObjectId,
|
||
"client_id": 1,
|
||
"uid": "ROLE0000000001",
|
||
"name": "管理員",
|
||
"status": 1,
|
||
"create_time": 1234567890,
|
||
"update_time": 1234567890
|
||
}
|
||
```
|
||
|
||
#### role_permissions
|
||
```json
|
||
{
|
||
"_id": ObjectId,
|
||
"role_id": ObjectId,
|
||
"permission_id": ObjectId,
|
||
"create_time": 1234567890,
|
||
"update_time": 1234567890
|
||
}
|
||
```
|
||
|
||
#### user_roles
|
||
```json
|
||
{
|
||
"_id": ObjectId,
|
||
"brand": "brand1",
|
||
"uid": "user123",
|
||
"role_id": "ROLE0000000001",
|
||
"status": 1,
|
||
"create_time": 1234567890,
|
||
"update_time": 1234567890
|
||
}
|
||
```
|
||
|
||
### Redis Keys
|
||
|
||
```
|
||
permission:access_token:{token_id} # Access Token
|
||
permission:refresh_token:{token_id} # Refresh Token
|
||
permission:device_token:{device_id} # Device Token List
|
||
permission:uid_token:{uid} # User Token List
|
||
permission:ticket:{ticket} # One-Time Token
|
||
permission:blacklist:{token_id} # Token Blacklist
|
||
``` |