mycasbin

package
v1.1.46 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Feb 23, 2026 License: Apache-2.0 Imports: 16 Imported by: 0

README

Casbin Multi-Tenant Support

This package provides Casbin enforcer setup with multi-tenant support.

Migration Guide

Old Usage (Deprecated)
// ❌ Old: Direct database connection
enforcer := mycasbin.Setup(db, "")
For security-management (Local Database)
// ✅ security-management uses local database
enforcer, err := mycasbin.SetupForTenant(db, tenantID)
For Microservices (Remote Provider)
// ✅ Microservices use remote provider
provider := grpc_client.NewGrpcCasbinPolicyProvider(connManager)
enforcer, err := mycasbin.SetupWithProvider(provider, tenantID)

API Reference

SetupForTenant
func SetupForTenant(db *gorm.DB, tenantID int) (*casbin.SyncedEnforcer, error)

Creates an independent Casbin enforcer for the specified tenant.

Parameters:

  • db: GORM database connection for the tenant's database
  • tenantID: Tenant identifier (used for logging and future Redis Watcher channel isolation)

Returns:

  • *casbin.SyncedEnforcer: Tenant-specific enforcer instance
  • error: Error if setup fails

Example:

db := getTenantDatabase(tenantID)
enforcer, err := mycasbin.SetupForTenant(db, tenantID)
if err != nil {
    return fmt.Errorf("租户 %d Casbin 初始化失败: %w", tenantID, err)
}

// Use enforcer for permission checks
allowed, err := enforcer.Enforce("user", "/api/v1/resource", "GET")
SetupWithProvider
func SetupWithProvider(provider PolicyProvider, tenantID int) (*casbin.SyncedEnforcer, error)

Creates a Casbin enforcer using a PolicyProvider instead of a database connection.

Parameters:

  • provider: Policy provider implementation (typically gRPC-based)
  • tenantID: Tenant identifier

Returns:

  • *casbin.SyncedEnforcer: Enforcer with loaded policies
  • error: Error if setup fails

Example:

provider := grpc_client.NewGrpcCasbinPolicyProvider(connManager)
enforcer, err := mycasbin.SetupWithProvider(provider, tenantID)
if err != nil {
    log.Fatalf("Casbin init failed: %v", err)
}

// Use enforcer for permission checks
allowed, err := enforcer.Enforce("user", "/api/v1/resource", "GET")

Usage:

  • For microservices (evidence-management, file-storage-service, tenant-service)
  • NOT for security-management (use SetupForTenant instead)
Setup (Deprecated)
func Setup(db *gorm.DB, _ string) *casbin.SyncedEnforcer

Legacy function for backward compatibility. Creates a single global enforcer.

Deprecated: Use SetupForTenant instead for proper multi-tenant support.

Redis Watcher

Each tenant gets a dedicated Redis channel for policy synchronization:

// Tenant 1 uses channel: /casbin/tenant/1
// Tenant 2 uses channel: /casbin/tenant/2
// etc.

When a tenant's policies are modified in the database:

  1. The modification publishes a message to /casbin/tenant/{tenantID}
  2. All instances running that tenant subscribe to the message
  3. Each instance's callback reloads policies from the tenant's database
  4. The enforcer is updated with the latest policies

Graceful Degradation:

  • If Redis is unavailable during SetupForTenant, the enforcer is still created successfully
  • A warning is logged, but the tenant can still function
  • Policy changes won't be auto-synchronized until Redis is available

Testing

Run tests:

# Unit tests (mock-based)
go test ./sdk/pkg/casbin/... -short

# Integration tests (requires test database)
go test ./sdk/pkg/casbin/... -v

# With coverage
go test ./sdk/pkg/casbin/... -cover -coverprofile=coverage.out

Known Issues

None (as of Stage 2). All multi-tenant isolation issues have been fixed.

Roadmap

  • Stage 1: Remove singleton, add SetupForTenant
  • Stage 2 (Current): Redis Watcher per-tenant isolation ✅
  • Stage 3: Update security-management to use new APIs (pending)

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Setup

func Setup(db *gorm.DB, _ string) *casbin.SyncedEnforcer

Setup 为指定租户创建 Casbin enforcer(向后兼容函数) 注意: 此函数保留用于向后兼容,新代码应使用 SetupForTenant Deprecated: 使用 SetupForTenant 替代,以获得更好的错误处理和多租户支持

func SetupForTenant added in v1.1.33

func SetupForTenant(db *gorm.DB, tenantID int) (*casbin.SyncedEnforcer, error)

SetupForTenant 为指定租户创建独立的 Casbin enforcer 每个租户拥有独立的 adapter、enforcer 实例和 Redis Watcher 频道

⚠️ 仅供 security-management 使用(本地数据库模式) 其他微服务请使用 SetupWithProvider

参数:

  • db: 该租户的数据库连接
  • tenantID: 租户ID(用于日志标识和 Redis Watcher 频道隔离)

返回:

  • *casbin.SyncedEnforcer: 该租户专属的 enforcer 实例
  • error: 错误信息

Redis Watcher:

  • 每个租户使用独立的 Redis 频道: /casbin/tenant/{tenantID}
  • 当租户的权限策略变更时,通过 Redis pub/sub 自动通知所有实例重新加载策略
  • Redis 不可用时,enforcer 仍能正常创建和使用(优雅降级)

func SetupWithProvider added in v1.1.35

func SetupWithProvider(provider PolicyProvider, tenantID int) (*casbin.SyncedEnforcer, error)

SetupWithProvider creates a Casbin enforcer using a PolicyProvider (for microservices) Unlike SetupForTenant, this does not require a local database connection

⚠️ For non-security-management microservices only (remote fetch mode) security-management should continue using SetupForTenant

Parameters:

  • provider: Policy provider (implemented by microservice, typically a gRPC adapter)
  • tenantID: Tenant identifier

Returns:

  • *casbin.SyncedEnforcer: Enforcer with loaded policies
  • error: Initialization error

Types

type Logger

type Logger struct {
	// contains filtered or unexported fields
}

Logger is the implementation for a Logger using zap logger.

func NewLogger added in v1.1.8

func NewLogger() *Logger

NewLogger creates a new Logger instance

func (*Logger) EnableLog

func (l *Logger) EnableLog(enable bool)

EnableLog controls whether print the message.

func (*Logger) IsEnabled

func (l *Logger) IsEnabled() bool

IsEnabled returns if logger is enabled.

func (*Logger) LogEnforce

func (l *Logger) LogEnforce(matcher string, request []interface{}, result bool, explains [][]string)

LogEnforce log info related to enforce.

func (*Logger) LogModel

func (l *Logger) LogModel(model [][]string)

LogModel log info related to model.

func (*Logger) LogPolicy

func (l *Logger) LogPolicy(policy map[string][][]string)

LogPolicy log info related to policy.

func (*Logger) LogRole

func (l *Logger) LogRole(roles []string)

LogRole log info related to role.

type PolicyProvider added in v1.1.35

type PolicyProvider interface {
	// GetPolicies retrieves all policy rules for the specified tenant
	//
	// Parameters:
	//   - ctx: Context (for timeout control, cancellation, etc.)
	//   - tenantID: Tenant identifier
	//
	// Returns:
	//   - []PolicyRule: List of policy rules (including both p and g types)
	//   - error: Error information
	GetPolicies(ctx context.Context, tenantID int) ([]PolicyRule, error)
}

PolicyProvider is the strategy interface for providing policy data Microservices implement this interface to supply policies from any source (gRPC, HTTP, DB, etc.)

type PolicyRule added in v1.1.35

type PolicyRule struct {
	PType string // Policy type: "p" (policy) or "g" (role inheritance)
	V0    string // Usually sub (role name)
	V1    string // Usually obj (resource path)
	V2    string // Usually act (HTTP method)
	V3    string // Optional extension field
	V4    string // Optional extension field
	V5    string // Optional extension field
}

PolicyRule represents a single Casbin policy rule.

Validation Rules:

  • PType must be a valid Casbin policy type: "p" (policy), "g" (role inheritance), etc.
  • V0-V5 fields must be filled contiguously from left to right without gaps
  • Empty strings at the end of the sequence are allowed (e.g., V3="", V4="", V5="")
  • Empty strings in the middle are NOT allowed (e.g., V0="admin", V1="", V2="GET" is invalid)

This format matches Casbin's standard storage schema (gorm-adapter).

type ProviderAdapter added in v1.1.35

type ProviderAdapter struct {
	// contains filtered or unexported fields
}

ProviderAdapter implements Casbin's persist.Adapter interface using a PolicyProvider This is a read-only adapter - write operations return errors

func NewProviderAdapter added in v1.1.35

func NewProviderAdapter(provider PolicyProvider, tenantID int) *ProviderAdapter

NewProviderAdapter creates a new ProviderAdapter

func (*ProviderAdapter) AddPolicy added in v1.1.35

func (a *ProviderAdapter) AddPolicy(sec string, ptype string, rule []string) error

AddPolicy is not supported (read-only adapter)

func (*ProviderAdapter) LoadPolicy added in v1.1.35

func (a *ProviderAdapter) LoadPolicy(m model.Model) error

LoadPolicy loads all policies from the Provider into the model This is called by Casbin SyncedEnforcer.LoadPolicy()

func (*ProviderAdapter) RemoveFilteredPolicy added in v1.1.35

func (a *ProviderAdapter) RemoveFilteredPolicy(sec string, ptype string, fieldIndex int, fieldValues ...string) error

RemoveFilteredPolicy is not supported (read-only adapter)

func (*ProviderAdapter) RemovePolicy added in v1.1.35

func (a *ProviderAdapter) RemovePolicy(sec string, ptype string, rule []string) error

RemovePolicy is not supported (read-only adapter)

func (*ProviderAdapter) SavePolicy added in v1.1.35

func (a *ProviderAdapter) SavePolicy(m model.Model) error

SavePolicy is not supported (read-only adapter)

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL