RBAC 实现
VEF Framework 提供了内置的基于角色的访问控制(RBAC)实现。
RBAC 概念
- 用户(User):系统的使用者
- 角色(Role):权限的集合
- 权限(Permission):执行特定操作的能力
配置 RBAC
实现 RolePermissionsLoader
go
package auth
import (
"my-app/internal/modules/system/models"
"github.com/ilxqx/vef-framework-go/auth"
"github.com/ilxqx/vef-framework-go/orm"
)
type RolePermissionsLoaderImpl struct{}
func NewRolePermissionsLoader() auth.RolePermissionsLoader {
return &RolePermissionsLoaderImpl{}
}
// LoadPermissions loads permissions for given roles
func (l *RolePermissionsLoaderImpl) LoadPermissions(roleIds []string) ([]string, error) {
var permissions []string
err := orm.DB().
Table("role_permissions").
Select("DISTINCT permission_token").
Where("role_id IN ?", roleIds).
Pluck("permission_token", &permissions).Error
if err != nil {
return nil, err
}
return permissions, nil
}注册 Loader
go
// In your module setup
func NewAuthModule() fx.Option {
return fx.Options(
fx.Provide(
auth.NewRolePermissionsLoader,
),
)
}角色模型
定义角色模型
go
package models
import "github.com/ilxqx/vef-framework-go/orm"
type Role struct {
orm.Model
Name string `gorm:"size:50;not null" json:"name"`
Code string `gorm:"size:50;uniqueIndex;not null" json:"code"`
Description string `gorm:"size:200" json:"description"`
IsActive bool `gorm:"default:true" json:"isActive"`
Permissions []Permission `gorm:"many2many:role_permissions" json:"permissions,omitempty"`
}
type Permission struct {
orm.Model
Name string `gorm:"size:50;not null" json:"name"`
Token string `gorm:"size:100;uniqueIndex;not null" json:"token"`
Module string `gorm:"size:50" json:"module"`
}
type RolePermission struct {
RoleId string `gorm:"primaryKey"`
PermissionId string `gorm:"primaryKey"`
}用户角色关联
go
type User struct {
orm.Model
Username string `gorm:"size:50;uniqueIndex;not null" json:"username"`
// ... other fields
Roles []Role `gorm:"many2many:user_roles" json:"roles,omitempty"`
}
type UserRole struct {
UserId string `gorm:"primaryKey"`
RoleId string `gorm:"primaryKey"`
}角色管理 API
创建角色资源
go
package resources
import (
"my-app/internal/modules/system/models"
"my-app/internal/modules/system/payloads"
"github.com/ilxqx/vef-framework-go/api"
"github.com/ilxqx/vef-framework-go/apis"
)
type RoleResource struct {
api.Resource
apis.FindPageApi[models.Role, payloads.RoleSearch]
apis.CreateApi[models.Role, payloads.RoleParams]
apis.UpdateApi[models.Role, payloads.RoleParams]
apis.DeleteApi[models.Role]
}
func NewRoleResource() api.Resource {
resource := &RoleResource{
Resource: api.NewResource("smp/sys/role"),
FindPageApi: apis.NewFindPageApi[models.Role, payloads.RoleSearch]().
WithPreload("Permissions"),
CreateApi: apis.NewCreateApi[models.Role, payloads.RoleParams](),
UpdateApi: apis.NewUpdateApi[models.Role, payloads.RoleParams](),
DeleteApi: apis.NewDeleteApi[models.Role](),
}
// Custom API for assigning permissions
resource.RegisterApiWithPermission(
"assign_permissions",
"role:assign_permissions",
resource.AssignPermissions,
)
return resource
}
func (r *RoleResource) AssignPermissions(ctx fiber.Ctx, params struct {
RoleId string `json:"roleId" validate:"required"`
PermissionIds []string `json:"permissionIds" validate:"required"`
}) error {
// Delete existing permissions
if err := orm.DB().
Where("role_id = ?", params.RoleId).
Delete(&models.RolePermission{}).Error; err != nil {
return api.Error(ctx, "Failed to update permissions")
}
// Insert new permissions
for _, permId := range params.PermissionIds {
rp := &models.RolePermission{
RoleId: params.RoleId,
PermissionId: permId,
}
if err := orm.DB().Create(rp).Error; err != nil {
return api.Error(ctx, "Failed to assign permission")
}
}
// Clear permission cache
auth.ClearAllPermissionCache()
return api.Success(ctx, nil)
}用户角色分配
go
func (r *UserResource) AssignRoles(ctx fiber.Ctx, params struct {
UserId string `json:"userId" validate:"required"`
RoleIds []string `json:"roleIds" validate:"required"`
}) error {
// Delete existing roles
if err := orm.DB().
Where("user_id = ?", params.UserId).
Delete(&models.UserRole{}).Error; err != nil {
return api.Error(ctx, "Failed to update roles")
}
// Insert new roles
for _, roleId := range params.RoleIds {
ur := &models.UserRole{
UserId: params.UserId,
RoleId: roleId,
}
if err := orm.DB().Create(ur).Error; err != nil {
return api.Error(ctx, "Failed to assign role")
}
}
// Clear permission cache for user
auth.ClearPermissionCache(params.UserId)
return api.Success(ctx, nil)
}权限树
构建权限树
go
type PermissionTree struct {
Id string `json:"id"`
Name string `json:"name"`
Token string `json:"token"`
Children []*PermissionTree `json:"children,omitempty"`
}
func BuildPermissionTree(permissions []models.Permission) []*PermissionTree {
// Group by module
moduleMap := make(map[string][]*PermissionTree)
for _, p := range permissions {
node := &PermissionTree{
Id: p.Id,
Name: p.Name,
Token: p.Token,
}
moduleMap[p.Module] = append(moduleMap[p.Module], node)
}
// Build tree
var tree []*PermissionTree
for module, perms := range moduleMap {
moduleNode := &PermissionTree{
Id: module,
Name: module,
Token: module + ":*",
Children: perms,
}
tree = append(tree, moduleNode)
}
return tree
}超级管理员
配置超级管理员
go
// Check if user is super admin
func (u *UserInfo) IsSuperAdmin() bool {
for _, roleId := range u.RoleIds {
if roleId == "super_admin" {
return true
}
}
return false
}
// Skip permission check for super admin
func (u *UserInfo) HasPermission(permission string) bool {
if u.IsSuperAdmin() {
return true
}
// Normal permission check
for _, p := range u.Permissions {
if p == permission {
return true
}
}
return false
}