package rbac import ( "fmt" "git.bvbej.com/bvbej/base-golang/pkg/rbac/model" "github.com/casbin/casbin/v2" casbinModel "github.com/casbin/casbin/v2/model" gormAdapter "github.com/casbin/gorm-adapter/v3" "github.com/gin-gonic/gin" "go.uber.org/zap" "gorm.io/gorm" "net/http" ) var _ Auth = (*auth)(nil) type Auth interface { AddRole(role, describe string) error DeleteRole(role string) (bool, error) AddRoleForUser(user, role string) (bool, error) UpdateRoleForUser(user, role string) (bool, error) UpdateRolePermission(role string, permissionIDs []uint64) (bool, error) CreatePermission(info gin.RoutesInfo) UpdatePermission(id uint64, url, description string) error CheckPermission(user string, r *http.Request) bool } type auth struct { db *gorm.DB enforcer *casbin.Enforcer logger *zap.Logger } func NewRBAC(db *gorm.DB, logger *zap.Logger) (Auth, error) { rule := new(model.RbacRules) gormAdapter.TurnOffAutoMigrate(db) t, err := gormAdapter.NewAdapterByDBWithCustomTable(db, rule, rule.TableName()) if err != nil { return nil, err } m, err := casbinModel.NewModelFromString(` [request_definition] r = sub, obj, act [policy_definition] p = sub, obj, act [role_definition] g = _, _ [policy_effect] e = some(where (p.eft == allow)) [matchers] m = g(r.sub, p.sub) && keyMatch(r.obj, p.obj) && (r.act == p.act || p.act == "*") || r.sub == "admin" `) if err != nil { return nil, err } enforcer, err := casbin.NewEnforcer(m, t) if err != nil { return nil, err } return &auth{ db: db, enforcer: enforcer, logger: logger, }, nil } func (a *auth) AddRole(role, describe string) error { if a.db.Where("name = ?", role).First(&model.RbacRoles{}).RowsAffected > 0 { return fmt.Errorf("角色已存在") } return a.db.Create(&model.RbacRoles{ Name: role, Describe: describe, }).Error } func (a *auth) DeleteRole(role string) (bool, error) { err := a.db.Where("name = ?", role).Delete(&model.RbacRoles{}).Error if err != nil { return false, err } return a.enforcer.DeleteRole(role) } func (a *auth) AddRoleForUser(user, role string) (bool, error) { return a.enforcer.AddRoleForUser(user, role) } func (a *auth) UpdateRoleForUser(user, role string) (bool, error) { oldRole, err := a.enforcer.GetRolesForUser(user) if err != nil && len(oldRole) > 0 { return false, err } oldRule := []string{user, oldRole[0]} newRule := []string{user, role} return a.enforcer.UpdateGroupingPolicy(oldRule, newRule) } func (a *auth) UpdateRolePermission(role string, permissionIDs []uint64) (bool, error) { ok, err := a.enforcer.DeletePermissionsForUser(role) if err != nil { return ok, err } var rbacPermissions []model.RbacPermissions a.db.Where("id IN ?", permissionIDs).Find(&rbacPermissions) if len(rbacPermissions) > 0 { var permissions [][]string for _, permission := range rbacPermissions { permissions = append(permissions, []string{permission.Path, permission.Method}) } return a.enforcer.AddPermissionsForUser(role, permissions...) } return false, fmt.Errorf("未找到需要添加的权限") } func (a *auth) CreatePermission(info gin.RoutesInfo) { for _, routeInfo := range info { a.db.Where("method = ? AND path = ?", routeInfo.Method, routeInfo.Path). FirstOrCreate(&model.RbacPermissions{ Method: routeInfo.Method, Path: routeInfo.Path, }) } } func (a *auth) UpdatePermission(id uint64, url, description string) error { return a.db.Where("id = ?", id).Updates(map[string]any{ "url": url, "description": description, }).Error } func (a *auth) CheckPermission(user string, r *http.Request) bool { path := r.URL.Path method := r.Method allowed, err := a.enforcer.Enforce(user, path, method) if err != nil { a.logger.Sugar().Errorf("Enforce err [%s]", err) return false } return allowed }