You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
OneAuth/重构设计.md

941 lines
33 KiB
Markdown

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

# vbase 用户权限系统重构设计
## 一、设计原则
1. **标准化**:遵循 OAuth2.0 / OIDC 标准协议
2. **无状态**:服务无状态,水平扩展友好
3. **安全性**密码bcrypt、JWT签名、HTTPS强制
4. **性能**Redis缓存热点数据1分钟TTL自动刷新
5. **可维护性**:清晰分层,单一职责
---
## 二、系统架构
```
┌─────────────────────────────────────────────────────────────┐
│ 接入层 │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────────────┐ │
│ │ REST API │ │ OAuth2.0 │ │ OIDC Discovery │ │
│ └──────┬──────┘ └──────┬──────┘ └──────────┬──────────┘ │
└─────────┼────────────────┼────────────────────┼────────────┘
│ │ │
┌─────────▼────────────────▼────────────────────▼────────────┐
│ 服务层 │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────────────┐ │
│ │ Auth服务 │ │ Org服务 │ │ OAuth服务 │ │
│ │ (认证) │ │ (组织) │ │ (第三方接入) │ │
│ └─────────────┘ └─────────────┘ └─────────────────────┘ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────────────┐ │
│ │ User服务 │ │ Role服务 │ │ Permission服务 │ │
│ │ (用户) │ │ (角色) │ │ (权限) │ │
│ └─────────────┘ └─────────────┘ └─────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
┌─────────▼──────────────────────────────────────────────────┐
│ 数据层 │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────────────┐ │
│ │ MySQL/PSQL │ │ Redis │ │ (可选)Etcd │ │
│ │ (主存储) │ │ (缓存/会话) │ │ (配置中心) │ │
│ └─────────────┘ └─────────────┘ └─────────────────────┘ │
└─────────────────────────────────────────────────────────────┘
```
---
## 三、核心数据模型
### 3.1 身份认证模型
```go
// User - 全局用户表
// 一个用户可属于多个组织,但登录是全局的
type User struct {
ID string `json:"id" gorm:"primaryKey;type:varchar(36)"`
Username string `json:"username" gorm:"uniqueIndex;size:50;not null"`
Password string `json:"-" gorm:"size:255"` // bcrypt hash第三方登录可为空
Nickname string `json:"nickname" gorm:"size:50"`
Avatar string `json:"avatar" gorm:"size:500"`
Email string `json:"email" gorm:"uniqueIndex;size:100"`
Phone string `json:"phone" gorm:"uniqueIndex;size:20"`
Status int `json:"status" gorm:"default:1"` // 0:禁用 1:正常 2:未激活
EmailVerified bool `json:"email_verified" gorm:"default:false"`
PhoneVerified bool `json:"phone_verified" gorm:"default:false"`
LastLoginAt *time.Time `json:"last_login_at"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
DeletedAt gorm.DeletedAt `json:"-" gorm:"index"`
}
// Identity - 第三方身份绑定
// 支持多种登录方式绑定到同一账号
type Identity struct {
ID string `json:"id" gorm:"primaryKey;type:varchar(36)"`
UserID string `json:"user_id" gorm:"index;not null"`
Provider string `json:"provider" gorm:"size:20;not null"` // google/github/wechat/ldap
ProviderUID string `json:"provider_uid" gorm:"index;size:100;not null"` // 第三方唯一ID
ProviderName string `json:"provider_name" gorm:"size:50"`
Avatar string `json:"avatar" gorm:"size:500"`
Email string `json:"email" gorm:"size:100"`
AccessToken string `json:"-" gorm:"size:500"` // 加密存储
RefreshToken string `json:"-" gorm:"size:500"`
ExpiresAt *time.Time `json:"-"`
CreatedAt time.Time `json:"created_at"`
}
// Session - 登录会话
// 用于多端登录管理和撤销
type Session struct {
ID string `json:"id" gorm:"primaryKey;type:varchar(36)"`
UserID string `json:"user_id" gorm:"index;not null"`
TokenID string `json:"token_id" gorm:"uniqueIndex;size:36"` // JWT jti
Type string `json:"type" gorm:"size:20;not null"` // access/refresh
DeviceInfo string `json:"device_info" gorm:"size:200"`
IP string `json:"ip" gorm:"size:50"`
ExpiresAt time.Time `json:"expires_at"`
Revoked bool `json:"revoked" gorm:"default:false"`
RevokedAt *time.Time `json:"revoked_at"`
CreatedAt time.Time `json:"created_at"`
}
```
### 3.2 组织架构模型
```go
// Org - 组织/租户
// 完全隔离的数据边界
type Org struct {
ID string `json:"id" gorm:"primaryKey;type:varchar(36)"`
Name string `json:"name" gorm:"size:50;not null"`
Code string `json:"code" gorm:"uniqueIndex;size:30;not null"` // 组织唯一编码
OwnerID string `json:"owner_id" gorm:"not null"` // 创建者/所有者
// 树形结构
ParentID *string `json:"parent_id" gorm:"index"`
Path string `json:"path" gorm:"size:500;index"` // 完整路径 /root/tech/backend
Level int `json:"level" gorm:"default:0"`
// 配置
Description string `json:"description" gorm:"size:200"`
Logo string `json:"logo" gorm:"size:500"`
Settings string `json:"-" gorm:"type:text"` // JSON配置
// 状态
Status int `json:"status" gorm:"default:1"` // 0:禁用 1:正常
MaxMembers int `json:"max_members" gorm:"default:100"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
// OrgMember - 组织成员关系
// 用户与组织的多对多关系
type OrgMember struct {
ID string `json:"id" gorm:"primaryKey;type:varchar(36)"`
OrgID string `json:"org_id" gorm:"uniqueIndex:idx_org_user;not null"`
UserID string `json:"user_id" gorm:"uniqueIndex:idx_org_user;not null"`
// 角色(多个角色,逗号分隔)
RoleIDs string `json:"role_ids" gorm:"size:200"`
// 成员信息
Position string `json:"position" gorm:"size:50"` // 职位
Department string `json:"department" gorm:"size:50"` // 部门名称(冗余)
JoinedAt time.Time `json:"joined_at"`
// 状态 0:待审核 1:正常 2:禁用
Status int `json:"status" gorm:"default:1"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
```
### 3.3 权限模型RBAC + ABAC
```go
// Role - 角色
// 组织级别的角色定义
type Role struct {
ID string `json:"id" gorm:"primaryKey;type:varchar(36)"`
OrgID string `json:"org_id" gorm:"index;not null"`
Code string `json:"code" gorm:"size:50;not null"` // 角色编码
Name string `json:"name" gorm:"size:50;not null"`
Description string `json:"description" gorm:"size:200"`
// 关联策略
PolicyIDs string `json:"policy_ids" gorm:"type:text"` // 逗号分隔
// 属性
IsDefault bool `json:"is_default" gorm:"default:false"` // 新成员默认角色
IsSystem bool `json:"is_system" gorm:"default:false"` // 系统内置(不可删)
SortOrder int `json:"sort_order" gorm:"default:0"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
// Policy - 策略
// 细粒度权限定义支持ABAC
type Policy struct {
ID string `json:"id" gorm:"primaryKey;type:varchar(36)"`
OrgID string `json:"org_id" gorm:"index"` // 空表示全局策略
Code string `json:"code" gorm:"uniqueIndex;size:50;not null"`
Name string `json:"name" gorm:"size:50;not null"`
Description string `json:"description" gorm:"size:200"`
// 资源定义
Resource string `json:"resource" gorm:"size:50;not null"` // 资源类型: user/org/member/role等
Action string `json:"action" gorm:"size:20;not null"` // read/create/update/delete/* /batch_create等
// ABAC条件CEL表达式
// 示例: "resource.owner == user.id" - 只能操作自己的资源
// 示例: "user.roles.exists(r, r == 'admin')" - 需要admin角色
// 示例: "resource.org_id == org.id" - 只能操作当前组织的资源
Condition string `json:"condition" gorm:"type:text"`
// 效果: allow/denydeny优先
Effect string `json:"effect" gorm:"size:10;default:allow"`
// 优先级数字越大优先级越高deny策略建议高优先级
Priority int `json:"priority" gorm:"default:0"`
IsSystem bool `json:"is_system" gorm:"default:false"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
```
### 3.4 OAuth2.0 模型
```go
// OAuthClient - 注册的应用客户端
type OAuthClient struct {
ID string `json:"id" gorm:"primaryKey;type:varchar(36)"`
Name string `json:"name" gorm:"size:50;not null"`
Description string `json:"description" gorm:"size:200"`
// 客户端凭证
ClientID string `json:"client_id" gorm:"uniqueIndex;size:32;not null"`
ClientSecret string `json:"-" gorm:"size:64;not null"`
// OAuth配置
RedirectURIs string `json:"redirect_uris" gorm:"type:text"` // 逗号分隔
GrantTypes string `json:"grant_types" gorm:"size:100"` // authorization_code/refresh_token/client_credentials
ResponseTypes string `json:"response_types" gorm:"size:50"` // code/token
// 访问控制
AllowedScopes string `json:"allowed_scopes" gorm:"size:200"` // openid profile email org roles
TokenExpiry int `json:"token_expiry" gorm:"default:3600"` // access_token有效期(秒)
RefreshExpiry int `json:"refresh_expiry" gorm:"default:2592000"` // refresh_token有效期(秒)
// 归属
OwnerID string `json:"owner_id" gorm:"not null"`
OrgID string `json:"org_id" gorm:"index"` // 可选,绑定特定组织
// 状态 0:禁用 1:正常
Status int `json:"status" gorm:"default:1"`
CreatedAt time.Time `json:"created_at"`
UpdatedAt time.Time `json:"updated_at"`
}
// OAuthAuthorization - 授权码存储
type OAuthAuthorization struct {
ID string `json:"id" gorm:"primaryKey;type:varchar(36)"`
UserID string `json:"user_id" gorm:"index;not null"`
ClientID string `json:"client_id" gorm:"index;not null"`
OrgID string `json:"org_id" gorm:"index"`
// 授权信息
Code string `json:"code" gorm:"uniqueIndex;size:64"`
Scope string `json:"scope" gorm:"size:200"`
State string `json:"state" gorm:"size:100"`
// PKCE
CodeChallenge string `json:"-" gorm:"size:128"`
CodeChallengeMethod string `json:"-" gorm:"size:10"`
// 状态
Used bool `json:"used" gorm:"default:false"`
UsedAt *time.Time `json:"used_at"`
ExpiresAt time.Time `json:"expires_at"`
CreatedAt time.Time `json:"created_at"`
}
// OAuthToken - OAuth访问令牌
type OAuthToken struct {
ID string `json:"id" gorm:"primaryKey;type:varchar(36)"`
UserID string `json:"user_id" gorm:"index;not null"`
ClientID string `json:"client_id" gorm:"index;not null"`
OrgID string `json:"org_id" gorm:"index"`
// Token信息
AccessToken string `json:"-" gorm:"uniqueIndex;size:64"`
RefreshToken string `json:"-" gorm:"uniqueIndex;size:64"`
TokenType string `json:"token_type" gorm:"size:10;default:Bearer"`
Scope string `json:"scope" gorm:"size:200"`
// 有效期
ExpiresAt time.Time `json:"expires_at"`
Revoked bool `json:"revoked" gorm:"default:false"`
RevokedAt *time.Time `json:"revoked_at"`
CreatedAt time.Time `json:"created_at"`
}
```
---
## 四、API 设计
### 4.1 路由结构
```
/api/v1
├── /auth # 认证相关(公开或需基础认证)
│ ├── POST /login
│ ├── POST /logout
│ ├── POST /refresh
│ ├── POST /register
│ ├── POST /forgot-password
│ ├── POST /reset-password
│ ├── GET /captcha
│ ├── GET /oauth/:provider # 第三方登录跳转
│ ├── GET /oauth/:provider/callback
│ └── POST /oauth/bind
├── /me # 当前用户(需认证)
│ ├── GET /
│ ├── PATCH /
│ ├── GET /sessions # 登录会话列表
│ ├── DELETE /sessions/:id # 撤销会话
│ ├── GET /identities # 绑定的第三方账号
│ ├── DELETE /identities/:provider # 解绑
│ ├── GET /orgs # 我的组织列表
│ └── POST /change-password
├── /users # 用户管理(需权限)
│ ├── GET /
│ ├── POST /
│ ├── GET /:id
│ ├── PATCH /:id
│ ├── DELETE /:id
│ └── PATCH /:id/status
├── /orgs # 组织管理
│ ├── GET / # 列表
│ ├── POST / # 创建(需登录)
│ ├── GET /:id
│ ├── PATCH /:id # 需组织管理员权限
│ ├── DELETE /:id
│ ├── GET /:id/tree # 组织树
│ ├── GET /:id/members # 成员列表
│ ├── POST /:id/members # 邀请成员
│ ├── GET /:id/members/:user_id
│ ├── PATCH /:id/members/:user_id # 修改角色/状态
│ ├── DELETE /:id/members/:user_id
│ ├── GET /:id/roles # 组织角色
│ ├── POST /:id/roles
│ └── GET /:id/policies # 组织策略
├── /roles # 角色管理(需组织上下文)
│ ├── GET /
│ ├── POST /
│ ├── GET /:id
│ ├── PATCH /:id
│ └── DELETE /:id
├── /policies # 策略管理
│ ├── GET /
│ ├── POST /
│ ├── GET /:id
│ ├── PATCH /:id
│ └── DELETE /:id
├── /oauth # OAuth2.0 服务端
│ ├── GET /authorize # 授权端点
│ ├── POST /token # 令牌端点
│ ├── POST /revoke # 撤销令牌
│ ├── GET /userinfo # 用户信息
│ ├── GET /.well-known/openid-configuration
│ ├── GET /.well-known/jwks.json
│ │
│ └── /clients # 客户端管理(需认证)
│ ├── GET /
│ ├── POST /
│ ├── GET /:id
│ ├── PATCH /:id
│ ├── DELETE /:id
│ └── POST /:id/reset-secret
└── /check # 权限检查(内部服务调用)
└── POST /permission # 检查指定权限
```
### 4.2 认证相关 API
#### POST /api/v1/auth/login
账号密码登录
```json
// Request
{
"username": "string", // 用户名/邮箱/手机号
"password": "string",
"captcha_id": "string", // 可选,错误多次后需要
"captcha_code": "string",
"remember": false // 是否长效token
}
// Response 200
{
"access_token": "eyJhbGciOiJSUzI1NiIs...",
"refresh_token": "dGhpcyBpcyBhIHJlZnJlc2g...",
"token_type": "Bearer",
"expires_in": 3600,
"user": {
"id": "uuid",
"username": "john",
"nickname": "John Doe",
"email": "john@example.com",
"avatar": "https://..."
}
}
```
#### POST /api/v1/auth/oauth/:provider
第三方登录返回跳转URL或直接302跳转
```json
// Query Params
?redirect_uri=https://app.com/callback&state=xyz
// Response (如果是SPA返回URL)
{
"auth_url": "https://accounts.google.com/o/oauth2/v2/auth..."
}
```
#### POST /api/v1/auth/oauth/bind
绑定第三方账号到已有账号
```json
// Request
{
"provider": "google",
"code": "authorization_code_from_provider",
"bind_type": "register" | "login", // 新注册还是绑定已有
"username": "string", // bind_type=register时需要
"password": "string" // bind_type=login时需要
}
// Response
{
"access_token": "...",
"user": {...}
}
```
### 4.3 组织相关 API
#### GET /api/v1/orgs
获取组织列表(用户加入的)
```json
// Response
{
"items": [
{
"id": "uuid",
"name": "技术部",
"code": "tech",
"logo": "https://...",
"owner_id": "uuid",
"member_count": 25,
"my_roles": ["admin", "developer"],
"joined_at": "2024-01-15T10:30:00Z"
}
]
}
```
#### POST /api/v1/orgs
创建组织
```json
// Request
{
"name": "新产品线",
"code": "new-product", // 唯一编码
"description": "...",
"logo": "https://..."
}
// Response
{
"id": "uuid",
"name": "新产品线",
"code": "new-product",
"owner_id": "current_user_id",
// 自动创建owner角色并分配
}
```
**注意**创建者自动成为组织所有者owner拥有所有权限。
### 4.4 权限相关 API
#### GET /api/v1/check/permissions
获取当前用户在指定组织的所有权限(用于前端按钮控制)
```json
// Query Params
?org_id=xxx
// Response
{
"org_id": "uuid",
"roles": ["admin", "developer"],
"permissions": [
"user:read",
"user:update:own",
"org:read",
"member:manage",
"role:read"
]
}
```
#### POST /api/v1/check/permission
检查具体权限(其他服务调用)
```json
// Request
{
"org_id": "uuid",
"resource": "user",
"action": "update",
"resource_id": "target_user_id" // 可选
}
// Response
{
"allowed": true,
"reason": "用户是资源所有者"
}
```
---
## 五、权限系统设计
### 5.1 策略表达式CEL
使用 [CEL (Common Expression Language)](https://github.com/google/cel-go) 作为条件表达式语言。
```go
// 内置变量
user // 当前用户对象
org // 当前组织对象
resource // 被访问资源对象
action // 动作: read/create/update/delete
// 示例策略条件
"true" // 无条件允许
"resource.created_by == user.id" // 只能操作自己创建的资源
"resource.owner_id == user.id" // 资源所有者
"org.members.exists(m, m.user_id == user.id && m.roles.exists(r, r.code == 'admin'))"
"user.id in org.owners" // 组织所有者
"resource.org_id == org.id" // 只能访问当前组织的资源
"resource.status == 'pending' && action == 'update'" // 特定状态才允许操作
```
### 5.2 系统内置策略
| 编码 | 资源 | 动作 | 条件 | 效果 | 说明 |
|------|------|------|------|------|------|
| `sys:user:read:own` | user | read | `resource.id == user.id` | allow | 读自己 |
| `sys:user:update:own` | user | update | `resource.id == user.id` | allow | 改自己 |
| `sys:org:admin` | org | * | `org.owner_id == user.id` | allow | 组织所有者 |
| `sys:member:read` | member | read | `resource.org_id == org.id` | allow | 读成员 |
| `sys:member:manage` | member | * | 需自定义角色 | allow | 管理成员 |
| `sys:role:read` | role | read | `resource.org_id == org.id` | allow | 读角色 |
| `sys:role:manage` | role | * | 需自定义角色 | allow | 管理角色 |
### 5.3 权限检查流程
```go
// 中间件流程
func PermissionMiddleware(resource, action string) vigo.Middleware {
return func(x *vigo.X) error {
// 1. 获取当前用户
user := auth.CurrentUser(x)
if user == nil {
return vigo.ErrUnauthorized
}
// 2. 获取当前组织从Header或Query
orgID := x.Request.Header.Get("X-Org-ID")
if orgID == "" {
orgID = x.Query("org_id")
}
// 3. 构建缓存key
cacheKey := fmt.Sprintf("perm:%s:%s:%s:%s", user.ID, orgID, resource, action)
// 4. 查缓存
if cached, err := redis.Get(cacheKey); err == nil {
if cached == "deny" {
return vigo.ErrForbidden
}
x.Set("permission_checked", true)
return x.Next()
}
// 5. 查询用户在该组织的角色
member := getOrgMember(orgID, user.ID)
if member == nil {
redis.Set(cacheKey, "deny", 1*time.Minute)
return vigo.ErrForbidden
}
// 6. 收集所有策略
policies := getPoliciesByRoles(member.RoleIDs)
// 7. 评估策略
allowed := evaluatePolicies(policies, user, org, resource, action)
// 8. 写入缓存
if allowed {
redis.Set(cacheKey, "allow", 1*time.Minute)
} else {
redis.Set(cacheKey, "deny", 1*time.Minute)
}
if !allowed {
return vigo.ErrForbidden
}
return x.Next()
}
}
```
---
## 六、OAuth2.0 / OIDC 实现
### 6.1 支持的授权流程
1. **Authorization Code Flow**推荐支持PKCE
- 用于服务端应用
- 支持 `code_challenge` (PKCE)
2. **Implicit Flow**(不推荐,但为了兼容支持)
- 用于纯前端应用建议迁移到PKCE
3. **Client Credentials Flow**
- 用于服务间调用
4. **Refresh Token**
- 用于刷新 access_token
### 6.2 OIDC 支持
- `/.well-known/openid-configuration` - 发现端点
- `/.well-known/jwks.json` - 公钥获取
- Scope: `openid profile email org roles`
- ID Token: JWT格式包含用户基本信息
### 6.3 授权流程示例
```
┌─────────────┐ ┌─────────────┐
│ 第三方应用 │ │ vbase │
└──────┬──────┘ └──────┬──────┘
│ │
│ 1. GET /oauth/authorize? │
│ response_type=code& │
│ client_id=xxx& │
│ redirect_uri=xxx& │
│ scope=openid profile org& │
│ state=xxx& │
│ code_challenge=xxx& │
│ code_challenge_method=S256 │
├─────────────────────────────────────────────────►│
│ │
│ 2. 未登录,重定向到登录页 │
│◄─────────────────────────────────────────────────┤
│ │
│ 3. 登录后,用户授权确认页面 │
│ (展示应用请求的权限范围) │
├─────────────────────────────────────────────────►│
│ │
│ 4. 302 重定向到 redirect_uri │
│ ?code=xxx&state=xxx │
│◄─────────────────────────────────────────────────┤
│ │
│ 5. POST /oauth/token │
│ grant_type=authorization_code& │
│ code=xxx& │
│ redirect_uri=xxx& │
│ client_id=xxx& │
│ client_secret=xxx& │
│ code_verifier=xxx (PKCE) │
├─────────────────────────────────────────────────►│
│ │
│ 6. 返回 Token │
│ { │
│ access_token: "...", │
│ id_token: "...", │
│ refresh_token: "...", │
│ token_type: "Bearer", │
│ expires_in: 3600 │
│ } │
│◄─────────────────────────────────────────────────┤
```
---
## 七、缓存策略
### 7.1 Redis 缓存结构
```
# 权限缓存(核心)
key: perm:{user_id}:{org_id}:{resource}:{action}
value: allow | deny
ttl: 60秒
# 用户信息缓存
key: user:{user_id}
value: JSON
ttl: 300秒
# 组织信息缓存
key: org:{org_id}
value: JSON
ttl: 300秒
# 组织成员缓存
key: org:{org_id}:member:{user_id}
value: JSON (包含角色ID列表)
ttl: 60秒
# 角色策略缓存
key: role:{role_id}:policies
value: JSON数组
ttl: 300秒
# Session/Token 黑名单(用于撤销)
key: token:revoked:{jti}
value: 1
ttl: 与token剩余有效期一致
# 限流计数
key: ratelimit:{ip}:{path}
value: 计数
ttl: 60秒
# 验证码
key: captcha:{captcha_id}
value: 验证码内容
ttl: 300秒
# OAuth 授权码
key: oauth:code:{code}
value: 授权信息JSON
ttl: 600秒
```
### 7.2 缓存更新策略
1. **被动失效**:数据变更时删除缓存
2. **主动刷新**TTL到期自动重新加载
3. **权限缓存**短TTL1分钟保证实时性
4. **配置缓存**长TTL5分钟减少DB查询
---
## 八、安全设计
### 8.1 密码安全
- **算法**bcryptcost=12
- **历史密码**不允许重复使用最近5次密码
- **复杂度**最小8位包含大小写+数字
- **传输**HTTPS only前端bcrypt预哈希可选
### 8.2 Token安全
- **Access Token**JWT RS256签名有效期1小时
- **Refresh Token**随机字符串有效期30天可撤销
- **Token绑定**:可选绑定设备指纹,防止盗用
- **撤销机制**JWT jti 存入黑名单实现撤销
### 8.3 OAuth安全
- **PKCE**所有public client强制启用
- **State参数**强制验证防止CSRF
- **Redirect URI**:必须预注册,严格匹配
- **Client Secret**仅用于confidential client
### 8.4 防护措施
- **限流**
- 登录5次/分钟错误5次后需要验证码
- 注册3次/小时
- API100次/分钟/用户
- **验证码**
- 图形验证码:登录错误多次后
- 邮箱/短信验证码:密码重置、敏感操作
- **审计日志**
- 登录/登出
- 密码修改
- 权限变更
- 组织重要操作
---
## 九、初始化流程
系统首次启动时自动执行:
1. **创建数据库表**
2. **创建超级管理员**
- 检测用户表是否为空
- 为空时创建默认超管账号
- 用户名/密码从环境变量读取(或随机生成并打印日志)
3. **创建系统策略**
- 创建所有系统内置策略
4. **创建默认组织**(可选)
- 创建名为"Default"的根组织
- 将超管加入该组织
---
## 十、技术选型
| 组件 | 选型 | 说明 |
|------|------|------|
| Web框架 | Vigo | 保持使用 |
| ORM | GORM | 保持使用 |
| 数据库 | MySQL/PostgreSQL | 保持使用 |
| 缓存 | Redis | 必选 |
| 密码哈希 | bcrypt | golang.org/x/crypto/bcrypt |
| JWT | jwt-go / golang-jwt | 标准库 |
| CEL表达式 | cel-go | github.com/google/cel-go |
| 验证码 | base64Captcha | 或自研 |
| OAuth2 | go-oauth2/oauth2 | 或自研实现 |
---
## 十一、目录结构
```
/
├── cmd/
│ └── server/
│ └── main.go # 服务入口
├── internal/ # 私有代码
│ ├── api/ # API层
│ │ ├── auth/ # 认证API
│ │ ├── user/ # 用户API
│ │ ├── org/ # 组织API
│ │ ├── role/ # 角色API
│ │ ├── policy/ # 策略API
│ │ ├── oauth/ # OAuth2.0服务端
│ │ └── middleware/ # 中间件
│ │ ├── auth.go # 认证中间件
│ │ ├── permission.go # 权限中间件
│ │ ├── ratelimit.go # 限流中间件
│ │ └── cors.go # 跨域中间件
│ ├── service/ # 业务逻辑层
│ │ ├── auth.go
│ │ ├── user.go
│ │ ├── org.go
│ │ ├── role.go
│ │ ├── policy.go
│ │ ├── permission.go # 权限检查核心
│ │ └── oauth.go
│ ├── model/ # 数据模型
│ │ ├── user.go
│ │ ├── org.go
│ │ ├── role.go
│ │ ├── policy.go
│ │ ├── oauth.go
│ │ └── migrate.go # 数据库迁移
│ ├── repository/ # 数据访问层
│ │ ├── user.go
│ │ ├── org.go
│ │ └── ...
│ ├── cache/ # 缓存封装
│ │ └── redis.go
│ ├── pkg/ # 内部工具包
│ │ ├── crypto/ # 加密工具
│ │ ├── jwt/ # JWT工具
│ │ ├── cel/ # CEL表达式
│ │ └── oauth/ # OAuth2工具
│ └── config/ # 配置
│ └── config.go
├── pkg/ # 可公开使用的包
│ └── sdk/ # 其他服务使用的SDK
├── docs/ # 文档
├── scripts/ # 脚本
├── configs/ # 配置文件
├── go.mod
└── README.md
```
---
## 十二、开发计划
### Phase 1: 基础架构
1. 数据库模型定义和迁移
2. Redis缓存封装
3. JWT认证中间件
4. 基础配置管理
### Phase 2: 认证模块
1. 用户注册/登录/登出
2. 密码管理
3. Session管理
4. 验证码
### Phase 3: 组织与成员
1. 组织CRUD
2. 成员管理
3. 组织树查询
### Phase 4: 权限系统
1. 策略定义
2. 角色管理
3. 权限检查中间件
4. CEL表达式评估
### Phase 5: OAuth2.0
1. 客户端管理
2. 授权流程
3. Token管理
4. OIDC支持
### Phase 6: 第三方登录
1. Google/GitHub/微信登录
2. 账号绑定
### Phase 7: 完善
1. 审计日志
2. 管理后台API
3. 测试和文档
---
**确认以上设计后开始Phase 1实现。**