在身份与访问管理(IAM)系统中,权限验证是核心功能,但随着业务发展,单一验证方式往往难以满足多样化需求。本文将通过实战案例,详解如何结合策略模式与工厂模式,构建灵活可扩展的权限验证架构,解决多策略动态切换、组合与扩展难题。

一、IAM系统的权限验证困境

随着企业数字化转型,IAM系统面临越来越复杂的权限验证场景:

  • 策略多样化:需要同时支持RBAC(基于角色)、ABAC(基于属性)、TBAC(基于任务)等多种验证逻辑
  • 动态切换需求:不同用户访问不同资源可能需要不同策略(如管理员用RBAC,普通用户用ABAC)
  • 扩展难题:新增策略时不想修改现有代码,符合开闭原则
  • 策略组合:敏感操作需要同时通过角色和属性双重验证
  • 性能优化:不同策略性能特征差异大(如RBAC缓存友好,ABAC计算密集)

这些问题如果用传统的if-else或单一继承实现,会导致代码臃肿、耦合严重,最终陷入"改一处动全身"的困境。

二、设计模式选型:策略模式+工厂模式

针对上述困境,我们选择两种设计模式组合解决:

  • 策略模式:封装不同验证算法,使它们可互换
  • 工厂模式:负责策略的创建与管理,实现策略类型与使用场景解耦

这种组合的核心优势在于:

  • 策略模式解决"如何定义不同验证逻辑"
  • 工厂模式解决"如何按需创建策略实例"
  • 二者结合实现"定义-创建-使用"的全流程解耦

三、实战实现:IAM权限验证架构

1. 策略接口抽象:定义统一行为

首先定义所有验证策略的通用接口,这是策略模式的核心:

// Authorizer 权限验证器接口(策略接口)
type Authorizer interface {
    // 核心方法:执行权限验证
    Authorize(ctx context.Context, attrs *RequestAttributes) (Decision, string, error)
    // 获取策略名称
    Name() string
    // 获取策略优先级(用于执行顺序控制)
    Priority() int
}

// 验证结果枚举
type Decision int
const (
    DecisionDeny   Decision = iota  // 拒绝
    DecisionAllow                   // 允许
    DecisionAbstain                 // 弃权(无意见)
)

// 验证请求属性(封装用户、资源、操作等信息)
type RequestAttributes struct {
    Username string            // 请求用户
    Resource string            // 访问资源
    Verb     string            // 操作类型(read/write/delete等)
    Path     string            // 请求路径
    Extra    map[string]string // 额外参数
}

接口设计要点:

  • Authorize方法标准化验证入口,所有策略实现统一签名
  • Priority用于控制策略执行顺序(性能优化关键)
  • RequestAttributes封装所有可能影响验证的上下文信息

2. 具体策略实现:封装多样化逻辑

RBAC策略实现(基于角色)
// RBACAuthorizer 基于角色的权限验证器
type RBACAuthorizer struct {
    store store.Factory // 数据存储接口
}

// NewRBACAuthorizer 创建RBAC验证器
func NewRBACAuthorizer(store store.Factory) *RBACAuthorizer {
    return &RBACAuthorizer{store: store}
}

// 核心验证逻辑:用户->角色->权限的映射检查
func (r *RBACAuthorizer) Authorize(ctx context.Context, attrs *RequestAttributes) (Decision, string, error) {
    log.Debugf("RBAC验证: 用户%s访问资源%s(%s)", attrs.Username, attrs.Resource, attrs.Verb)
    
    // 1. 获取用户角色
    roles, err := r.getUserRoles(ctx, attrs.Username)
    if err != nil {
        return DecisionDeny, "", fmt.Errorf("获取角色失败: %w", err)
    }
    
    // 2. 检查角色是否有权限
    for _, role := range roles {
        if r.hasPermission(ctx, role, attrs.Resource, attrs.Verb) {
            return DecisionAllow, "RBAC验证通过", nil
        }
    }
    
    return DecisionDeny, "RBAC验证拒绝", nil
}

// 实现接口其他方法
func (r *RBACAuthorizer) Name() string      { return "RBACAuthorizer" }
func (r *RBACAuthorizer) Priority() int     { return 100 } // 中等优先级

// 从存储获取用户角色(简化实现)
func (r *RBACAuthorizer) getUserRoles(ctx context.Context, username string) ([]string, error) {
    // 实际应查询数据库/缓存:user_roles表
    return []string{"admin"}, nil
}

// 检查角色是否有指定资源的操作权限
func (r *RBACAuthorizer) hasPermission(ctx context.Context, role, resource, verb string) bool {
    // 实际应查询:role_permissions表
    return role == "admin" // 示例:管理员拥有所有权限
}
ABAC策略实现(基于属性)
// ABACAuthorizer 基于属性的权限验证器
type ABACAuthorizer struct {
    store store.Factory
}

// 核心验证逻辑:用户属性与资源属性的匹配检查
func (a *ABACAuthorizer) Authorize(ctx context.Context, attrs *RequestAttributes) (Decision, string, error) {
    log.Debugf("ABAC验证: 用户%s访问资源%s(%s)", attrs.Username, attrs.Resource, attrs.Verb)
    
    // 1. 获取用户属性
    userAttrs, err := a.getUserAttributes(ctx, attrs.Username)
    if err != nil {
        return DecisionDeny, "", fmt.Errorf("获取用户属性失败: %w", err)
    }
    
    // 2. 获取资源属性
    resourceAttrs, err := a.getResourceAttributes(ctx, attrs.Resource)
    if err != nil {
        return DecisionDeny, "", fmt.Errorf("获取资源属性失败: %w", err)
    }
    
    // 3. 执行属性匹配策略
    if a.evaluatePolicy(userAttrs, resourceAttrs, attrs.Verb) {
        return DecisionAllow, "ABAC验证通过", nil
    }
    
    return DecisionDeny, "ABAC验证拒绝", nil
}

// 实现接口其他方法
func (a *ABACAuthorizer) Name() string    { return "ABACAuthorizer" }
func (a *ABACAuthorizer) Priority() int   { return 200 } // 高优先级

// 属性匹配规则(示例)
func (a *ABACAuthorizer) evaluatePolicy(userAttrs, resourceAttrs map[string]interface{}, verb string) bool {
    // 规则1:用户部门与资源部门匹配(或资源对所有部门开放)
    if userDept, ok1 := userAttrs["department"].(string); ok1 {
        if resourceDept, ok2 := resourceAttrs["department"].(string); ok2 {
            if resourceDept == "all" || userDept == resourceDept {
                return true
            }
        }
    }
    
    // 规则2:管理员级别用户拥有所有权限
    if userLevel, ok := userAttrs["level"].(string); ok && userLevel == "admin" {
        return true
    }
    
    return false
}
TBAC策略实现(基于任务)
// TBACAuthorizer 基于任务的权限验证器
type TBACAuthorizer struct {
    store store.Factory
}

// 核心验证逻辑:检查用户是否有有效的任务授权
func (t *TBACAuthorizer) Authorize(ctx context.Context, attrs *RequestAttributes) (Decision, string, error) {
    log.Debugf("TBAC验证: 用户%s访问资源%s(%s)", attrs.Username, attrs.Resource, attrs.Verb)
    
    // 1. 获取用户的活跃任务
    task, err := t.getUserActiveTask(ctx, attrs.Username, attrs.Resource)
    if err != nil {
        return DecisionDeny, "", fmt.Errorf("获取活跃任务失败: %w", err)
    }
    
    // 2. 任务不存在则拒绝
    if task == nil {
        return DecisionDeny, "无相关活跃任务", nil
    }
    
    // 3. 检查任务有效期
    if time.Now().After(task.ExpireAt) {
        return DecisionDeny, "任务已过期", nil
    }
    
    // 4. 检查任务允许的操作
    if !t.isOperationAllowed(task, attrs.Verb) {
        return DecisionDeny, "任务不允许此操作", nil
    }
    
    return DecisionAllow, "TBAC验证通过", nil
}

// 实现接口其他方法
func (t *TBACAuthorizer) Name() string    { return "TBACAuthorizer" }
func (t *TBACAuthorizer) Priority() int   { return 150 } // 中高优先级

3. 工厂模式:策略的创建与管理

为了解决策略实例的创建复杂性,我们实现一个策略工厂:

// AuthorizerFactory 策略工厂接口
type AuthorizerFactory interface {
    CreateAuthorizer(strategyType StrategyType) (Authorizer, error)       // 创建单个策略
    CreateAuthorizers(strategyTypes []StrategyType) ([]Authorizer, error) // 创建多个策略
    RegisterAuthorizer(strategyType StrategyType, creator AuthorizerCreator) // 注册新策略
}

// 策略创建函数类型
type AuthorizerCreator func(store store.Factory) Authorizer

// 工厂实现
type authorizerFactory struct {
    store    store.Factory
    creators map[StrategyType]AuthorizerCreator // 策略类型到创建函数的映射
    mutex    sync.RWMutex                       // 并发安全锁
}

// 初始化工厂并注册默认策略
func NewAuthorizerFactory(store store.Factory) AuthorizerFactory {
    factory := &authorizerFactory{
        store:    store,
        creators: make(map[StrategyType]AuthorizerCreator),
    }
    
    // 注册内置策略
    factory.RegisterAuthorizer(RBACStrategyType, func(store store.Factory) Authorizer {
        return NewRBACAuthorizer(store)
    })
    factory.RegisterAuthorizer(ABACStrategyType, func(store store.Factory) Authorizer {
        return NewABACAuthorizer(store)
    })
    factory.RegisterAuthorizer(TBACStrategyType, func(store store.Factory) Authorizer {
        return NewTBACAuthorizer(store)
    })
    
    return factory
}

// 创建指定类型的策略实例
func (f *authorizerFactory) CreateAuthorizer(strategyType StrategyType) (Authorizer, error) {
    f.mutex.RLock()
    creator, exists := f.creators[strategyType]
    f.mutex.RUnlock()
    
    if !exists {
        return nil, fmt.Errorf("未注册的策略类型: %s", strategyType)
    }
    
    return creator(f.store), nil
}

工厂模式的核心价值:

  • 集中管理策略创建逻辑,避免在业务代码中分散new操作
  • 通过RegisterAuthorizer支持动态扩展新策略(插件化思想)
  • 结合sync.RWMutex保证并发安全,适合高并发场景

4. 策略组合:应对复杂验证场景

很多时候单一策略无法满足需求,需要组合多种策略验证。我们用组合模式实现这一功能:

// CompositeAuthorizer 组合策略验证器
type CompositeAuthorizer struct {
    authorizers []Authorizer       // 包含的子策略
    strategy    CompositeStrategy  // 组合方式
}

// 组合策略类型
type CompositeStrategy string
const (
    AllAllowStrategy CompositeStrategy = "all_allow" // 所有策略允许才算通过
    AnyAllowStrategy CompositeStrategy = "any_allow" // 任一策略允许就算通过
)

// 执行组合验证
func (c *CompositeAuthorizer) Authorize(ctx context.Context, attrs *RequestAttributes) (Decision, string, error) {
    switch c.strategy {
    case AllAllowStrategy:
        return c.authorizeAllAllow(ctx, attrs)
    case AnyAllowStrategy:
        return c.authorizeAnyAllow(ctx, attrs)
    default:
        return c.authorizeAnyAllow(ctx, attrs)
    }
}

// 所有策略允许才算通过(适用于高安全场景)
func (c *CompositeAuthorizer) authorizeAllAllow(ctx context.Context, attrs *RequestAttributes) (Decision, string, error) {
    var reasons []string
    
    for _, authorizer := range c.authorizers {
        decision, reason, err := authorizer.Authorize(ctx, attrs)
        if err != nil {
            return DecisionDeny, "", fmt.Errorf("策略%s执行失败: %w", authorizer.Name(), err)
        }
        
        reasons = append(reasons, fmt.Sprintf("%s: %s", authorizer.Name(), reason))
        
        // 任一策略拒绝则整体拒绝
        if decision == DecisionDeny {
            return DecisionDeny, strings.Join(reasons, "; "), nil
        }
    }
    
    return DecisionAllow, strings.Join(reasons, "; "), nil
}

// 任一策略允许就算通过(适用于高可用场景)
func (c *CompositeAuthorizer) authorizeAnyAllow(ctx context.Context, attrs *RequestAttributes) (Decision, string, error) {
    var reasons []string
    
    for _, authorizer := range c.authorizers {
        decision, reason, err := authorizer.Authorize(ctx, attrs)
        if err != nil {
            return DecisionDeny, "", fmt.Errorf("策略%s执行失败: %w", authorizer.Name(), err)
        }
        
        reasons = append(reasons, fmt.Sprintf("%s: %s", authorizer.Name(), reason))
        
        // 任一策略允许则整体允许
        if decision == DecisionAllow {
            return DecisionAllow, strings.Join(reasons, "; "), nil
        }
    }
    
    return DecisionDeny, strings.Join(reasons, "; "), nil
}

5. 策略管理器:动态选择与调度

最后实现一个管理器,负责根据请求动态选择合适的策略:

// Manager 策略管理器
type Manager struct {
    factory        AuthorizerFactory
    store          store.Factory
    defaultStrategy StrategyType
    mutex          sync.RWMutex
}

// 执行权限验证的入口方法
func (m *Manager) Authorize(ctx context.Context, attrs *RequestAttributes) (Decision, string, error) {
    // 1. 动态确定使用的策略类型
    strategyType := m.determineStrategy(attrs)
    
    // 2. 创建对应的策略实例
    var authorizer Authorizer
    var err error
    if strategyType == CompositeStrategyType {
        authorizer, err = m.createCompositeAuthorizer(attrs)
    } else {
        authorizer, err = m.factory.CreateAuthorizer(strategyType)
    }
    
    if err != nil {
        return DecisionDeny, "", fmt.Errorf("创建策略失败: %w", err)
    }
    
    // 3. 执行验证
    return authorizer.Authorize(ctx, attrs)
}

// 动态确定策略类型的核心逻辑
func (m *Manager) determineStrategy(attrs *RequestAttributes) StrategyType {
    // 优先使用请求中指定的策略
    if strategy, ok := attrs.Extra["strategy"]; ok {
        switch StrategyType(strategy) {
        case RBACStrategyType, ABACStrategyType, TBACStrategyType, CompositeStrategyType:
            return StrategyType(strategy)
        }
    }
    
    // 按资源类型自动选择策略
    if strings.HasPrefix(attrs.Resource, "task/") {
        return TBACStrategyType // 任务类资源用TBAC
    }
    if strings.HasPrefix(attrs.Resource, "sensitive/") {
        return ABACStrategyType // 敏感资源用ABAC
    }
    
    // 默认策略
    return m.defaultStrategy
}

四、配置与集成:在IAM系统中落地

1. 配置文件支持

通过配置文件定义策略的启用状态和优先级:

# iam-authz-server.yaml
authorization:
  default-strategy: rbac  # 默认策略
  strategies:
    - name: rbac
      enabled: true
      priority: 100
    - name: abac
      enabled: true
      priority: 200
    - name: tbac
      enabled: true
      priority: 150

2. 主服务集成

在IAM服务中初始化并使用策略管理器:

// 创建IAM服务实例
func createAuthzServer(cfg *config.Config) (*authzServer, error) {
    // ... 其他初始化逻辑
    
    // 获取数据存储工厂
    mysqlFactory, err := mysql.GetMySQLFactoryOr(cfg.MySQLOptions)
    if err != nil {
        return nil, err
    }
    
    // 初始化策略管理器
    defaultStrategy := authorization.StrategyType(cfg.Authorization.DefaultStrategy)
    if defaultStrategy == "" {
        defaultStrategy = authorization.RBACStrategyType
    }
    authzManager := authorization.NewManager(mysqlFactory, defaultStrategy)
    
    // 注册自定义策略(如果有)
    authzManager.RegisterAuthorizer("custom", func(store store.Factory) authorization.Authorizer {
        return NewCustomAuthorizer(store)
    })
    
    return &authzServer{
        // ... 其他字段
        authorizer: authzManager,
    }, nil
}

// 处理权限验证请求
func (s *authzServer) Authorize(ctx context.Context, req *pb.AuthorizeRequest) (*pb.AuthorizeResponse, error) {
    // 构造验证请求属性
    attrs := &authorization.RequestAttributes{
        Username: req.Username,
        Resource: req.Resource,
        Verb:     req.Verb,
        Path:     req.Path,
        Extra:    req.Extra,
    }
    
    // 调用策略管理器执行验证
    decision, reason, err := s.authorizer.Authorize(ctx, attrs)
    if err != nil {
        return nil, fmt.Errorf("验证失败: %w", err)
    }
    
    return &pb.AuthorizeResponse{
        Username: req.Username,
        Allowed:  decision == authorization.DecisionAllow,
        Reason:   reason,
    }, nil
}

五、方案优势总结

通过策略模式与工厂模式的结合,我们的IAM权限验证系统获得了以下优势:

  1. 极致解耦:策略定义、创建、使用完全分离,单个策略的修改不影响其他组件
  2. 动态灵活:可根据请求属性自动选择策略,支持运行时动态切换
  3. 轻松扩展:新增策略只需实现Authorizer接口并注册,无需修改核心代码
  4. 组合能力:支持多种策略组合验证,满足复杂业务场景
  5. 性能可控:通过优先级控制策略执行顺序,优先执行高性能策略
  6. 可维护性:每个策略独立封装,职责单一,便于测试和优化

这种设计特别适合IAM这类需要长期演进、场景复杂的系统,能够有效应对业务增长带来的权限验证挑战。

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐