策略模式+工厂模式:IAM系统复杂权限验证的优雅解决方案
·
在身份与访问管理(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权限验证系统获得了以下优势:
- 极致解耦:策略定义、创建、使用完全分离,单个策略的修改不影响其他组件
- 动态灵活:可根据请求属性自动选择策略,支持运行时动态切换
- 轻松扩展:新增策略只需实现
Authorizer接口并注册,无需修改核心代码 - 组合能力:支持多种策略组合验证,满足复杂业务场景
- 性能可控:通过优先级控制策略执行顺序,优先执行高性能策略
- 可维护性:每个策略独立封装,职责单一,便于测试和优化
这种设计特别适合IAM这类需要长期演进、场景复杂的系统,能够有效应对业务增长带来的权限验证挑战。
更多推荐

所有评论(0)