feat(permission): add RBAC module with Casbin enforcement and policy reload
- Multi-tenant RBAC: permission catalog, roles, role-permission mapping,
user-role assignment, and external IdP role mapping (zitadel/ldap/scim).
- Casbin enforcer with Redis-backed adapter and Pub/Sub reload for
multi-instance policy sync; HTTP middleware enforces (tenant, role,
path, method) with platform admin bypass.
- /api/v1/permissions routes: catalog, me, policy/reload, roles CRUD,
role permissions, user roles, role mappings.
- New error scope (31) for Permission and biz code descriptions.
- Wire Permission module into ServiceContext, config, mongo-index, and
add cmd/permission-seed CLI plus etc/rbac.conf model.
- Redis client gains lazy PubSubClient helper (go-zero wrapper lacks Subscribe).
- Rewrite internal/model/member/README to cover Tenant/Member/Identity.
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-21 08:47:35 +00:00
|
|
|
package domain
|
|
|
|
|
|
|
|
|
|
import "strings"
|
|
|
|
|
|
|
|
|
|
// RedisKey is the permission module Redis key prefix. Use the package-level
|
|
|
|
|
// helpers (Get*RedisKey) instead of string concatenation so the layout stays
|
|
|
|
|
// auditable.
|
|
|
|
|
type RedisKey string
|
|
|
|
|
|
|
|
|
|
// Key prefixes for the permission module. Layout matches
|
2026-05-22 09:18:08 +00:00
|
|
|
// internal/model/permission/SDD.md §4.1 (Redis Keys).
|
feat(permission): add RBAC module with Casbin enforcement and policy reload
- Multi-tenant RBAC: permission catalog, roles, role-permission mapping,
user-role assignment, and external IdP role mapping (zitadel/ldap/scim).
- Casbin enforcer with Redis-backed adapter and Pub/Sub reload for
multi-instance policy sync; HTTP middleware enforces (tenant, role,
path, method) with platform admin bypass.
- /api/v1/permissions routes: catalog, me, policy/reload, roles CRUD,
role permissions, user roles, role mappings.
- New error scope (31) for Permission and biz code descriptions.
- Wire Permission module into ServiceContext, config, mongo-index, and
add cmd/permission-seed CLI plus etc/rbac.conf model.
- Redis client gains lazy PubSubClient helper (go-zero wrapper lacks Subscribe).
- Rewrite internal/model/member/README to cover Tenant/Member/Identity.
Co-authored-by: Cursor <cursoragent@cursor.com>
2026-05-21 08:47:35 +00:00
|
|
|
const (
|
|
|
|
|
CasbinRulesRedisKey RedisKey = "permission:casbin:rules"
|
|
|
|
|
UserRolesRedisKey RedisKey = "perm:user_roles"
|
|
|
|
|
RolePermsRedisKey RedisKey = "perm:role_perms"
|
|
|
|
|
PermissionTreeKey RedisKey = "permission:tree:open"
|
|
|
|
|
PolicyReloadLockKey RedisKey = "permission:policy:reload:lock"
|
|
|
|
|
StepUpUsedRedisKey RedisKey = "permission:stepup:used"
|
|
|
|
|
PermissionAuthGenKey RedisKey = "auth:gen"
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
// With appends colon-separated parts to the key.
|
|
|
|
|
func (key RedisKey) With(parts ...string) RedisKey {
|
|
|
|
|
if len(parts) == 0 {
|
|
|
|
|
return key
|
|
|
|
|
}
|
|
|
|
|
return RedisKey(string(key) + ":" + strings.Join(parts, ":"))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// String returns the raw key.
|
|
|
|
|
func (key RedisKey) String() string {
|
|
|
|
|
return string(key)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// GetCasbinRulesRedisKey returns the tenant-scoped Casbin policy list key.
|
|
|
|
|
func GetCasbinRulesRedisKey(tenantID string) string {
|
|
|
|
|
return CasbinRulesRedisKey.With(tenantID).String()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// GetUserRolesRedisKey returns the cache key for a user's role keys.
|
|
|
|
|
func GetUserRolesRedisKey(tenantID, uid string) string {
|
|
|
|
|
return UserRolesRedisKey.With(tenantID, uid).String()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// GetRolePermsRedisKey returns the cache key for a role's permission names.
|
|
|
|
|
func GetRolePermsRedisKey(tenantID, roleID string) string {
|
|
|
|
|
return RolePermsRedisKey.With(tenantID, roleID).String()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// GetAuthGenRedisKey returns the auth_gen revocation counter key. It mirrors
|
|
|
|
|
// the auth module's namespace because permission changes also bump auth_gen.
|
|
|
|
|
func GetAuthGenRedisKey(tenantID, uid string) string {
|
|
|
|
|
return PermissionAuthGenKey.With(tenantID, uid).String()
|
|
|
|
|
}
|