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

33 KiB

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 身份认证模型

// 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 组织架构模型

// 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

// 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 模型

// 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

账号密码登录

// 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跳转

// 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

绑定第三方账号到已有账号

// 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

获取组织列表(用户加入的)

// 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

创建组织

// 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

获取当前用户在指定组织的所有权限(用于前端按钮控制)

// 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

检查具体权限(其他服务调用)

// Request
{
    "org_id": "uuid",
    "resource": "user",
    "action": "update",
    "resource_id": "target_user_id"  // 可选
}

// Response
{
    "allowed": true,
    "reason": "用户是资源所有者"
}

五、权限系统设计

5.1 策略表达式CEL

使用 CEL (Common Expression Language) 作为条件表达式语言。

// 内置变量
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 权限检查流程

// 中间件流程
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 TokenJWT 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实现。