package repository import ( "context" "encoding/json" "time" "code.30cm.net/digimon/app-cloudep-permission-server/pkg/domain" "code.30cm.net/digimon/app-cloudep-permission-server/pkg/domain/rbac" "code.30cm.net/digimon/app-cloudep-permission-server/pkg/domain/repository" "github.com/casbin/casbin/v2/model" "github.com/casbin/casbin/v2/persist" "github.com/zeromicro/go-zero/core/stores/redis" ) type RBACAdapterParam struct { Redis *redis.Redis } type rbacAdapter struct { redis *redis.Redis } func NewRBACAdapter(param RBACAdapterParam) (repository.RBACAdapter, error) { return &rbacAdapter{ redis: param.Redis, }, nil } // loadPolicyByString 真正將 Rule 存到 casbin 讓他可以使用的地方 func loadPolicyByString(line rbac.Rule, model model.Model) error { text := line.ToString() // 雖然是從Redis 來,不過最終還是有一份會存在記憶體當中,這樣做的原因只是不要存第二次 err := persist.LoadPolicyArray(text, model) if err != nil { return err } return nil } // LoadPolicy 將檔案從記憶體當中載入本地 Casbin func (adapter *rbacAdapter) LoadPolicy(model model.Model) error { ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second) defer cancel() rk := domain.GetCasbinRuleRedisKey() stop, err := adapter.redis.LlenCtx(ctx, rk) if err != nil { return err } rules, err := adapter.redis.LrangeCtx(ctx, rk, 0, stop) if err != nil { return err } for _, ruleStr := range rules { var rule rbac.Rule err := json.Unmarshal([]byte(ruleStr), &rule) if err != nil { return err } err = loadPolicyByString(rule, model) if err != nil { return err } } return nil } // SavePolicy saves policy to database. 將 Rule 一次就從資料庫中存到 redis 裡面 -> 打API 初始化 Redis 同步的資料 func (adapter *rbacAdapter) SavePolicy(model model.Model) error { rk := domain.GetCasbinRuleRedisKey() _, err := adapter.redis.Del(rk) if err != nil { return err } var texts []string for policy, ast := range model["p"] { for _, rule := range ast.Policy { line := rbac.StringToPolicy(policy, rule) text, err := json.Marshal(line) if err != nil { return err } texts = append(texts, string(text)) } } for policy, ast := range model["g"] { for _, rule := range ast.Policy { line := rbac.StringToPolicy(policy, rule) text, err := json.Marshal(line) if err != nil { return err } texts = append(texts, string(text)) } } _, err = adapter.redis.Rpush(rk, texts) if err != nil { return err } return nil } // AddPolicy adds a policy rule to the storage. func (adapter *rbacAdapter) AddPolicy(_ string, policyType string, rule []string) error { policy := rbac.StringToPolicy(policyType, rule) text, err := json.Marshal(policy) if err != nil { return err } rk := domain.GetCasbinRuleRedisKey() _, err = adapter.redis.Rpush(rk, text) if err != nil { return err } return nil } func (adapter *rbacAdapter) RemovePolicy(_ string, policyType string, rule []string) error { policy := rbac.StringToPolicy(policyType, rule) text, err := json.Marshal(policy) if err != nil { return err } rk := domain.GetCasbinRuleRedisKey() _, err = adapter.redis.Lrem(rk, 1, string(text)) if err != nil { return err } return nil } // RemoveFilteredPolicy 沒用到先不實作 func (adapter *rbacAdapter) RemoveFilteredPolicy(_ string, _ string, _ int, _ ...string) error { return nil }