3.9.4 RBAC 权限控制

3.9.4 RBAC 权限控制 #

基于角色的访问控制(Role-Based Access Control,RBAC)是一种广泛使用的权限管理模型。它通过角色来组织权限,用户通过分配角色来获得相应的权限,实现了权限管理的灵活性和可维护性。

RBAC 基础概念 #

RBAC 模型组成 #

RBAC 模型包含以下核心概念:

  1. 用户(User):系统的使用者
  2. 角色(Role):权限的集合,代表一种职能
  3. 权限(Permission):对资源的操作权限
  4. 资源(Resource):系统中的受保护对象
  5. 操作(Action):对资源可执行的动作

RBAC 关系模型 #

用户 ←→ 角色 ←→ 权限 ←→ 资源
  ↓      ↓      ↓      ↓
User   Role   Permission Resource

RBAC 层次结构 #

  • RBAC0:基础模型,包含用户、角色、权限和会话
  • RBAC1:角色层次模型,支持角色继承
  • RBAC2:约束模型,支持职责分离等约束
  • RBAC3:统一模型,结合 RBAC1 和 RBAC2

Go 中实现 RBAC #

数据模型设计 #

// models/rbac.go
package models

import (
    "time"
    "gorm.io/gorm"
)

// User 用户模型
type User struct {
    ID        uint      `json:"id" gorm:"primaryKey"`
    Username  string    `json:"username" gorm:"unique;not null"`
    Email     string    `json:"email" gorm:"unique;not null"`
    Password  string    `json:"-" gorm:"not null"`
    IsActive  bool      `json:"is_active" gorm:"default:true"`
    Roles     []Role    `json:"roles" gorm:"many2many:user_roles;"`
    CreatedAt time.Time `json:"created_at"`
    UpdatedAt time.Time `json:"updated_at"`
}

// Role 角色模型
type Role struct {
    ID          uint         `json:"id" gorm:"primaryKey"`
    Name        string       `json:"name" gorm:"unique;not null"`
    DisplayName string       `json:"display_name" gorm:"not null"`
    Description string       `json:"description"`
    IsActive    bool         `json:"is_active" gorm:"default:true"`
    Users       []User       `json:"users" gorm:"many2many:user_roles;"`
    Permissions []Permission `json:"permissions" gorm:"many2many:role_permissions;"`
    ParentID    *uint        `json:"parent_id" gorm:"index"`
    Parent      *Role        `json:"parent" gorm:"foreignKey:ParentID"`
    Children    []Role       `json:"children" gorm:"foreignKey:ParentID"`
    CreatedAt   time.Time    `json:"created_at"`
    UpdatedAt   time.Time    `json:"updated_at"`
}

// Permission 权限模型
type Permission struct {
    ID          uint       `json:"id" gorm:"primaryKey"`
    Name        string     `json:"name" gorm:"unique;not null"`
    DisplayName string     `json:"display_name" gorm:"not null"`
    Description string     `json:"description"`
    Resource    string     `json:"resource" gorm:"not null"`
    Action      string     `json:"action" gorm:"not null"`
    IsActive    bool       `json:"is_active" gorm:"default:true"`
    Roles       []Role     `json:"roles" gorm:"many2many:role_permissions;"`
    CreatedAt   time.Time  `json:"created_at"`
    UpdatedAt   time.Time  `json:"updated_at"`
}

// UserRole 用户角色关联表
type UserRole struct {
    UserID    uint      `json:"user_id" gorm:"primaryKey"`
    RoleID    uint      `json:"role_id" gorm:"primaryKey"`
    AssignedBy uint     `json:"assigned_by"`
    AssignedAt time.Time `json:"assigned_at"`
    ExpiresAt  *time.Time `json:"expires_at"`
}

// RolePermission 角色权限关联表
type RolePermission struct {
    RoleID       uint      `json:"role_id" gorm:"primaryKey"`
    PermissionID uint      `json:"permission_id" gorm:"primaryKey"`
    GrantedBy    uint      `json:"granted_by"`
    GrantedAt    time.Time `json:"granted_at"`
}

// Resource 资源模型
type Resource struct {
    ID          uint      `json:"id" gorm:"primaryKey"`
    Name        string    `json:"name" gorm:"unique;not null"`
    DisplayName string    `json:"display_name" gorm:"not null"`
    Description string    `json:"description"`
    Type        string    `json:"type" gorm:"not null"` // api, menu, button, data
    Path        string    `json:"path"`
    Method      string    `json:"method"`
    ParentID    *uint     `json:"parent_id" gorm:"index"`
    Parent      *Resource `json:"parent" gorm:"foreignKey:ParentID"`
    Children    []Resource `json:"children" gorm:"foreignKey:ParentID"`
    IsActive    bool      `json:"is_active" gorm:"default:true"`
    CreatedAt   time.Time `json:"created_at"`
    UpdatedAt   time.Time `json:"updated_at"`
}

RBAC 服务层 #

// services/rbac.go
package services

import (
    "errors"
    "fmt"
    "strings"
    "time"

    "gorm.io/gorm"
    "your-project/models"
)

var (
    ErrUserNotFound       = errors.New("用户不存在")
    ErrRoleNotFound       = errors.New("角色不存在")
    ErrPermissionNotFound = errors.New("权限不存在")
    ErrPermissionDenied   = errors.New("权限不足")
    ErrRoleExists         = errors.New("角色已存在")
    ErrPermissionExists   = errors.New("权限已存在")
)

// RBACService RBAC服务
type RBACService struct {
    db *gorm.DB
}

// NewRBACService 创建RBAC服务
func NewRBACService(db *gorm.DB) *RBACService {
    return &RBACService{db: db}
}

// CreateRole 创建角色
func (s *RBACService) CreateRole(role *models.Role) error {
    var existingRole models.Role
    if err := s.db.Where("name = ?", role.Name).First(&existingRole).Error; err == nil {
        return ErrRoleExists
    }

    return s.db.Create(role).Error
}

// GetRole 获取角色
func (s *RBACService) GetRole(roleID uint) (*models.Role, error) {
    var role models.Role
    if err := s.db.Preload("Permissions").Preload("Users").First(&role, roleID).Error; err != nil {
        if err == gorm.ErrRecordNotFound {
            return nil, ErrRoleNotFound
        }
        return nil, err
    }
    return &role, nil
}

// GetRoleByName 根据名称获取角色
func (s *RBACService) GetRoleByName(name string) (*models.Role, error) {
    var role models.Role
    if err := s.db.Preload("Permissions").Where("name = ?", name).First(&role).Error; err != nil {
        if err == gorm.ErrRecordNotFound {
            return nil, ErrRoleNotFound
        }
        return nil, err
    }
    return &role, nil
}

// CreatePermission 创建权限
func (s *RBACService) CreatePermission(permission *models.Permission) error {
    var existingPermission models.Permission
    if err := s.db.Where("name = ?", permission.Name).First(&existingPermission).Error; err == nil {
        return ErrPermissionExists
    }

    return s.db.Create(permission).Error
}

// GetPermission 获取权限
func (s *RBACService) GetPermission(permissionID uint) (*models.Permission, error) {
    var permission models.Permission
    if err := s.db.First(&permission, permissionID).Error; err != nil {
        if err == gorm.ErrRecordNotFound {
            return nil, ErrPermissionNotFound
        }
        return nil, err
    }
    return &permission, nil
}

// AssignRoleToUser 为用户分配角色
func (s *RBACService) AssignRoleToUser(userID, roleID, assignedBy uint) error {
    // 检查用户是否存在
    var user models.User
    if err := s.db.First(&user, userID).Error; err != nil {
        return ErrUserNotFound
    }

    // 检查角色是否存在
    var role models.Role
    if err := s.db.First(&role, roleID).Error; err != nil {
        return ErrRoleNotFound
    }

    // 检查是否已经分配
    var userRole models.UserRole
    if err := s.db.Where("user_id = ? AND role_id = ?", userID, roleID).First(&userRole).Error; err == nil {
        return errors.New("用户已拥有该角色")
    }

    // 创建用户角色关联
    userRole = models.UserRole{
        UserID:     userID,
        RoleID:     roleID,
        AssignedBy: assignedBy,
        AssignedAt: time.Now(),
    }

    return s.db.Create(&userRole).Error
}

// RevokeRoleFromUser 撤销用户角色
func (s *RBACService) RevokeRoleFromUser(userID, roleID uint) error {
    return s.db.Where("user_id = ? AND role_id = ?", userID, roleID).Delete(&models.UserRole{}).Error
}

// AssignPermissionToRole 为角色分配权限
func (s *RBACService) AssignPermissionToRole(roleID, permissionID, grantedBy uint) error {
    // 检查角色是否存在
    var role models.Role
    if err := s.db.First(&role, roleID).Error; err != nil {
        return ErrRoleNotFound
    }

    // 检查权限是否存在
    var permission models.Permission
    if err := s.db.First(&permission, permissionID).Error; err != nil {
        return ErrPermissionNotFound
    }

    // 检查是否已经分配
    var rolePermission models.RolePermission
    if err := s.db.Where("role_id = ? AND permission_id = ?", roleID, permissionID).First(&rolePermission).Error; err == nil {
        return errors.New("角色已拥有该权限")
    }

    // 创建角色权限关联
    rolePermission = models.RolePermission{
        RoleID:       roleID,
        PermissionID: permissionID,
        GrantedBy:    grantedBy,
        GrantedAt:    time.Now(),
    }

    return s.db.Create(&rolePermission).Error
}

// RevokePermissionFromRole 撤销角色权限
func (s *RBACService) RevokePermissionFromRole(roleID, permissionID uint) error {
    return s.db.Where("role_id = ? AND permission_id = ?", roleID, permissionID).Delete(&models.RolePermission{}).Error
}

// GetUserRoles 获取用户角色
func (s *RBACService) GetUserRoles(userID uint) ([]models.Role, error) {
    var user models.User
    if err := s.db.Preload("Roles.Permissions").First(&user, userID).Error; err != nil {
        return nil, ErrUserNotFound
    }

    return user.Roles, nil
}

// GetUserPermissions 获取用户权限(包括角色继承)
func (s *RBACService) GetUserPermissions(userID uint) ([]models.Permission, error) {
    roles, err := s.GetUserRoles(userID)
    if err != nil {
        return nil, err
    }

    permissionMap := make(map[uint]models.Permission)

    for _, role := range roles {
        // 获取角色直接权限
        for _, permission := range role.Permissions {
            permissionMap[permission.ID] = permission
        }

        // 获取角色继承权限
        inheritedPermissions, err := s.getRoleInheritedPermissions(role.ID)
        if err != nil {
            continue
        }

        for _, permission := range inheritedPermissions {
            permissionMap[permission.ID] = permission
        }
    }

    permissions := make([]models.Permission, 0, len(permissionMap))
    for _, permission := range permissionMap {
        permissions = append(permissions, permission)
    }

    return permissions, nil
}

// getRoleInheritedPermissions 获取角色继承的权限
func (s *RBACService) getRoleInheritedPermissions(roleID uint) ([]models.Permission, error) {
    var role models.Role
    if err := s.db.Preload("Parent.Permissions").First(&role, roleID).Error; err != nil {
        return nil, err
    }

    var permissions []models.Permission

    // 递归获取父角色权限
    if role.Parent != nil {
        permissions = append(permissions, role.Parent.Permissions...)

        parentPermissions, err := s.getRoleInheritedPermissions(role.Parent.ID)
        if err == nil {
            permissions = append(permissions, parentPermissions...)
        }
    }

    return permissions, nil
}

// CheckPermission 检查用户权限
func (s *RBACService) CheckPermission(userID uint, resource, action string) (bool, error) {
    permissions, err := s.GetUserPermissions(userID)
    if err != nil {
        return false, err
    }

    for _, permission := range permissions {
        if permission.Resource == resource && permission.Action == action {
            return true, nil
        }

        // 支持通配符权限
        if permission.Resource == "*" || permission.Action == "*" {
            return true, nil
        }

        // 支持资源层次权限
        if strings.HasPrefix(resource, permission.Resource+".") {
            return true, nil
        }
    }

    return false, nil
}

// CheckRole 检查用户角色
func (s *RBACService) CheckRole(userID uint, roleName string) (bool, error) {
    roles, err := s.GetUserRoles(userID)
    if err != nil {
        return false, err
    }

    for _, role := range roles {
        if role.Name == roleName {
            return true, nil
        }
    }

    return false, nil
}

// GetRoleHierarchy 获取角色层次结构
func (s *RBACService) GetRoleHierarchy() ([]models.Role, error) {
    var roles []models.Role
    if err := s.db.Preload("Children").Where("parent_id IS NULL").Find(&roles).Error; err != nil {
        return nil, err
    }

    return roles, nil
}

RBAC 中间件 #

// middleware/rbac.go
package middleware

import (
    "net/http"
    "strings"

    "github.com/gin-gonic/gin"
    "your-project/services"
)

// RBACMiddleware RBAC权限中间件
func RBACMiddleware(rbacService *services.RBACService) gin.HandlerFunc {
    return func(c *gin.Context) {
        // 获取用户ID(假设已通过认证中间件设置)
        userID, exists := c.Get("user_id")
        if !exists {
            c.JSON(http.StatusUnauthorized, gin.H{
                "error": "未认证用户",
            })
            c.Abort()
            return
        }

        // 将RBAC服务添加到上下文
        c.Set("rbac_service", rbacService)
        c.Set("current_user_id", userID)

        c.Next()
    }
}

// RequirePermission 要求特定权限的中间件
func RequirePermission(resource, action string) gin.HandlerFunc {
    return func(c *gin.Context) {
        rbacService, exists := c.Get("rbac_service")
        if !exists {
            c.JSON(http.StatusInternalServerError, gin.H{
                "error": "RBAC服务未初始化",
            })
            c.Abort()
            return
        }

        userID, exists := c.Get("current_user_id")
        if !exists {
            c.JSON(http.StatusUnauthorized, gin.H{
                "error": "用户未认证",
            })
            c.Abort()
            return
        }

        service := rbacService.(*services.RBACService)
        hasPermission, err := service.CheckPermission(userID.(uint), resource, action)
        if err != nil {
            c.JSON(http.StatusInternalServerError, gin.H{
                "error": "权限检查失败",
            })
            c.Abort()
            return
        }

        if !hasPermission {
            c.JSON(http.StatusForbidden, gin.H{
                "error": "权限不足",
                "required_permission": map[string]string{
                    "resource": resource,
                    "action":   action,
                },
            })
            c.Abort()
            return
        }

        c.Next()
    }
}

// RequireRole 要求特定角色的中间件
func RequireRole(roleName string) gin.HandlerFunc {
    return func(c *gin.Context) {
        rbacService, exists := c.Get("rbac_service")
        if !exists {
            c.JSON(http.StatusInternalServerError, gin.H{
                "error": "RBAC服务未初始化",
            })
            c.Abort()
            return
        }

        userID, exists := c.Get("current_user_id")
        if !exists {
            c.JSON(http.StatusUnauthorized, gin.H{
                "error": "用户未认证",
            })
            c.Abort()
            return
        }

        service := rbacService.(*services.RBACService)
        hasRole, err := service.CheckRole(userID.(uint), roleName)
        if err != nil {
            c.JSON(http.StatusInternalServerError, gin.H{
                "error": "角色检查失败",
            })
            c.Abort()
            return
        }

        if !hasRole {
            c.JSON(http.StatusForbidden, gin.H{
                "error": "角色权限不足",
                "required_role": roleName,
            })
            c.Abort()
            return
        }

        c.Next()
    }
}

// RequireAnyRole 要求任意角色的中间件
func RequireAnyRole(roleNames ...string) gin.HandlerFunc {
    return func(c *gin.Context) {
        rbacService, exists := c.Get("rbac_service")
        if !exists {
            c.JSON(http.StatusInternalServerError, gin.H{
                "error": "RBAC服务未初始化",
            })
            c.Abort()
            return
        }

        userID, exists := c.Get("current_user_id")
        if !exists {
            c.JSON(http.StatusUnauthorized, gin.H{
                "error": "用户未认证",
            })
            c.Abort()
            return
        }

        service := rbacService.(*services.RBACService)

        for _, roleName := range roleNames {
            hasRole, err := service.CheckRole(userID.(uint), roleName)
            if err == nil && hasRole {
                c.Next()
                return
            }
        }

        c.JSON(http.StatusForbidden, gin.H{
            "error": "角色权限不足",
            "required_roles": roleNames,
        })
        c.Abort()
    }
}

// DynamicPermissionMiddleware 动态权限中间件
func DynamicPermissionMiddleware() gin.HandlerFunc {
    return func(c *gin.Context) {
        rbacService, exists := c.Get("rbac_service")
        if !exists {
            c.JSON(http.StatusInternalServerError, gin.H{
                "error": "RBAC服务未初始化",
            })
            c.Abort()
            return
        }

        userID, exists := c.Get("current_user_id")
        if !exists {
            c.JSON(http.StatusUnauthorized, gin.H{
                "error": "用户未认证",
            })
            c.Abort()
            return
        }

        // 根据请求路径和方法动态确定所需权限
        resource := getResourceFromPath(c.FullPath())
        action := getActionFromMethod(c.Request.Method)

        service := rbacService.(*services.RBACService)
        hasPermission, err := service.CheckPermission(userID.(uint), resource, action)
        if err != nil {
            c.JSON(http.StatusInternalServerError, gin.H{
                "error": "权限检查失败",
            })
            c.Abort()
            return
        }

        if !hasPermission {
            c.JSON(http.StatusForbidden, gin.H{
                "error": "权限不足",
                "required_permission": map[string]string{
                    "resource": resource,
                    "action":   action,
                },
            })
            c.Abort()
            return
        }

        c.Next()
    }
}

// getResourceFromPath 从路径获取资源名
func getResourceFromPath(path string) string {
    parts := strings.Split(strings.Trim(path, "/"), "/")
    if len(parts) >= 3 {
        return parts[2] // /api/v1/users -> users
    }
    return "unknown"
}

// getActionFromMethod 从HTTP方法获取操作名
func getActionFromMethod(method string) string {
    switch method {
    case "GET":
        return "read"
    case "POST":
        return "create"
    case "PUT", "PATCH":
        return "update"
    case "DELETE":
        return "delete"
    default:
        return "unknown"
    }
}

RBAC 控制器 #

// controllers/rbac.go
package controllers

import (
    "net/http"
    "strconv"

    "github.com/gin-gonic/gin"
    "your-project/models"
    "your-project/services"
)

type RBACController struct {
    rbacService *services.RBACService
}

func NewRBACController(rbacService *services.RBACService) *RBACController {
    return &RBACController{
        rbacService: rbacService,
    }
}

// CreateRole 创建角色
func (ctrl *RBACController) CreateRole(c *gin.Context) {
    var req struct {
        Name        string `json:"name" binding:"required"`
        DisplayName string `json:"display_name" binding:"required"`
        Description string `json:"description"`
        ParentID    *uint  `json:"parent_id"`
    }

    if err := c.ShouldBindJSON(&req); err != nil {
        c.JSON(http.StatusBadRequest, gin.H{
            "error": err.Error(),
        })
        return
    }

    role := &models.Role{
        Name:        req.Name,
        DisplayName: req.DisplayName,
        Description: req.Description,
        ParentID:    req.ParentID,
    }

    if err := ctrl.rbacService.CreateRole(role); err != nil {
        c.JSON(http.StatusConflict, gin.H{
            "error": err.Error(),
        })
        return
    }

    c.JSON(http.StatusCreated, gin.H{
        "message": "角色创建成功",
        "role":    role,
    })
}

// GetRoles 获取角色列表
func (ctrl *RBACController) GetRoles(c *gin.Context) {
    roles, err := ctrl.rbacService.GetRoleHierarchy()
    if err != nil {
        c.JSON(http.StatusInternalServerError, gin.H{
            "error": "获取角色列表失败",
        })
        return
    }

    c.JSON(http.StatusOK, gin.H{
        "roles": roles,
    })
}

// CreatePermission 创建权限
func (ctrl *RBACController) CreatePermission(c *gin.Context) {
    var req struct {
        Name        string `json:"name" binding:"required"`
        DisplayName string `json:"display_name" binding:"required"`
        Description string `json:"description"`
        Resource    string `json:"resource" binding:"required"`
        Action      string `json:"action" binding:"required"`
    }

    if err := c.ShouldBindJSON(&req); err != nil {
        c.JSON(http.StatusBadRequest, gin.H{
            "error": err.Error(),
        })
        return
    }

    permission := &models.Permission{
        Name:        req.Name,
        DisplayName: req.DisplayName,
        Description: req.Description,
        Resource:    req.Resource,
        Action:      req.Action,
    }

    if err := ctrl.rbacService.CreatePermission(permission); err != nil {
        c.JSON(http.StatusConflict, gin.H{
            "error": err.Error(),
        })
        return
    }

    c.JSON(http.StatusCreated, gin.H{
        "message": "权限创建成功",
        "permission": permission,
    })
}

// AssignRoleToUser 为用户分配角色
func (ctrl *RBACController) AssignRoleToUser(c *gin.Context) {
    userIDStr := c.Param("user_id")
    userID, err := strconv.ParseUint(userIDStr, 10, 32)
    if err != nil {
        c.JSON(http.StatusBadRequest, gin.H{
            "error": "无效的用户ID",
        })
        return
    }

    var req struct {
        RoleID uint `json:"role_id" binding:"required"`
    }

    if err := c.ShouldBindJSON(&req); err != nil {
        c.JSON(http.StatusBadRequest, gin.H{
            "error": err.Error(),
        })
        return
    }

    currentUserID, _ := c.Get("current_user_id")

    if err := ctrl.rbacService.AssignRoleToUser(uint(userID), req.RoleID, currentUserID.(uint)); err != nil {
        c.JSON(http.StatusBadRequest, gin.H{
            "error": err.Error(),
        })
        return
    }

    c.JSON(http.StatusOK, gin.H{
        "message": "角色分配成功",
    })
}

// RevokeRoleFromUser 撤销用户角色
func (ctrl *RBACController) RevokeRoleFromUser(c *gin.Context) {
    userIDStr := c.Param("user_id")
    userID, err := strconv.ParseUint(userIDStr, 10, 32)
    if err != nil {
        c.JSON(http.StatusBadRequest, gin.H{
            "error": "无效的用户ID",
        })
        return
    }

    roleIDStr := c.Param("role_id")
    roleID, err := strconv.ParseUint(roleIDStr, 10, 32)
    if err != nil {
        c.JSON(http.StatusBadRequest, gin.H{
            "error": "无效的角色ID",
        })
        return
    }

    if err := ctrl.rbacService.RevokeRoleFromUser(uint(userID), uint(roleID)); err != nil {
        c.JSON(http.StatusBadRequest, gin.H{
            "error": err.Error(),
        })
        return
    }

    c.JSON(http.StatusOK, gin.H{
        "message": "角色撤销成功",
    })
}

// AssignPermissionToRole 为角色分配权限
func (ctrl *RBACController) AssignPermissionToRole(c *gin.Context) {
    roleIDStr := c.Param("role_id")
    roleID, err := strconv.ParseUint(roleIDStr, 10, 32)
    if err != nil {
        c.JSON(http.StatusBadRequest, gin.H{
            "error": "无效的角色ID",
        })
        return
    }

    var req struct {
        PermissionID uint `json:"permission_id" binding:"required"`
    }

    if err := c.ShouldBindJSON(&req); err != nil {
        c.JSON(http.StatusBadRequest, gin.H{
            "error": err.Error(),
        })
        return
    }

    currentUserID, _ := c.Get("current_user_id")

    if err := ctrl.rbacService.AssignPermissionToRole(uint(roleID), req.PermissionID, currentUserID.(uint)); err != nil {
        c.JSON(http.StatusBadRequest, gin.H{
            "error": err.Error(),
        })
        return
    }

    c.JSON(http.StatusOK, gin.H{
        "message": "权限分配成功",
    })
}

// GetUserPermissions 获取用户权限
func (ctrl *RBACController) GetUserPermissions(c *gin.Context) {
    userIDStr := c.Param("user_id")
    userID, err := strconv.ParseUint(userIDStr, 10, 32)
    if err != nil {
        c.JSON(http.StatusBadRequest, gin.H{
            "error": "无效的用户ID",
        })
        return
    }

    permissions, err := ctrl.rbacService.GetUserPermissions(uint(userID))
    if err != nil {
        c.JSON(http.StatusInternalServerError, gin.H{
            "error": err.Error(),
        })
        return
    }

    c.JSON(http.StatusOK, gin.H{
        "permissions": permissions,
    })
}

// CheckPermission 检查用户权限
func (ctrl *RBACController) CheckPermission(c *gin.Context) {
    userIDStr := c.Param("user_id")
    userID, err := strconv.ParseUint(userIDStr, 10, 32)
    if err != nil {
        c.JSON(http.StatusBadRequest, gin.H{
            "error": "无效的用户ID",
        })
        return
    }

    resource := c.Query("resource")
    action := c.Query("action")

    if resource == "" || action == "" {
        c.JSON(http.StatusBadRequest, gin.H{
            "error": "缺少resource或action参数",
        })
        return
    }

    hasPermission, err := ctrl.rbacService.CheckPermission(uint(userID), resource, action)
    if err != nil {
        c.JSON(http.StatusInternalServerError, gin.H{
            "error": err.Error(),
        })
        return
    }

    c.JSON(http.StatusOK, gin.H{
        "has_permission": hasPermission,
        "resource":       resource,
        "action":         action,
    })
}

权限初始化 #

// pkg/rbac/init.go
package rbac

import (
    "log"
    "your-project/models"
    "your-project/services"
)

// InitializeRBAC 初始化RBAC系统
func InitializeRBAC(rbacService *services.RBACService) error {
    // 创建基础角色
    roles := []models.Role{
        {
            Name:        "super_admin",
            DisplayName: "超级管理员",
            Description: "系统超级管理员,拥有所有权限",
        },
        {
            Name:        "admin",
            DisplayName: "管理员",
            Description: "系统管理员",
        },
        {
            Name:        "user",
            DisplayName: "普通用户",
            Description: "普通用户",
        },
        {
            Name:        "guest",
            DisplayName: "访客",
            Description: "访客用户",
        },
    }

    for _, role := range roles {
        if err := rbacService.CreateRole(&role); err != nil {
            log.Printf("创建角色失败: %v", err)
        }
    }

    // 创建基础权限
    permissions := []models.Permission{
        // 用户管理权限
        {Name: "user.create", DisplayName: "创建用户", Resource: "user", Action: "create"},
        {Name: "user.read", DisplayName: "查看用户", Resource: "user", Action: "read"},
        {Name: "user.update", DisplayName: "更新用户", Resource: "user", Action: "update"},
        {Name: "user.delete", DisplayName: "删除用户", Resource: "user", Action: "delete"},

        // 角色管理权限
        {Name: "role.create", DisplayName: "创建角色", Resource: "role", Action: "create"},
        {Name: "role.read", DisplayName: "查看角色", Resource: "role", Action: "read"},
        {Name: "role.update", DisplayName: "更新角色", Resource: "role", Action: "update"},
        {Name: "role.delete", DisplayName: "删除角色", Resource: "role", Action: "delete"},

        // 权限管理权限
        {Name: "permission.create", DisplayName: "创建权限", Resource: "permission", Action: "create"},
        {Name: "permission.read", DisplayName: "查看权限", Resource: "permission", Action: "read"},
        {Name: "permission.update", DisplayName: "更新权限", Resource: "permission", Action: "update"},
        {Name: "permission.delete", DisplayName: "删除权限", Resource: "permission", Action: "delete"},

        // 系统权限
        {Name: "system.admin", DisplayName: "系统管理", Resource: "system", Action: "admin"},
        {Name: "system.monitor", DisplayName: "系统监控", Resource: "system", Action: "monitor"},

        // 通配符权限
        {Name: "all.all", DisplayName: "所有权限", Resource: "*", Action: "*"},
    }

    for _, permission := range permissions {
        if err := rbacService.CreatePermission(&permission); err != nil {
            log.Printf("创建权限失败: %v", err)
        }
    }

    // 为角色分配权限
    rolePermissions := map[string][]string{
        "super_admin": {"all.all"},
        "admin": {
            "user.create", "user.read", "user.update", "user.delete",
            "role.read", "permission.read",
            "system.monitor",
        },
        "user": {
            "user.read",
        },
        "guest": {},
    }

    for roleName, permissionNames := range rolePermissions {
        role, err := rbacService.GetRoleByName(roleName)
        if err != nil {
            continue
        }

        for _, permissionName := range permissionNames {
            // 这里需要根据权限名称获取权限ID,然后分配
            // 简化处理,实际应用中需要完善
            log.Printf("为角色 %s 分配权限 %s", roleName, permissionName)
        }
    }

    return nil
}

完整示例 #

// main.go
package main

import (
    "log"

    "github.com/gin-gonic/gin"
    "gorm.io/driver/sqlite"
    "gorm.io/gorm"

    "your-project/controllers"
    "your-project/middleware"
    "your-project/models"
    "your-project/pkg/rbac"
    "your-project/services"
)

func main() {
    // 初始化数据库
    db, err := gorm.Open(sqlite.Open("rbac.db"), &gorm.Config{})
    if err != nil {
        log.Fatal("数据库连接失败:", err)
    }

    // 自动迁移
    db.AutoMigrate(
        &models.User{},
        &models.Role{},
        &models.Permission{},
        &models.Resource{},
        &models.UserRole{},
        &models.RolePermission{},
    )

    // 初始化服务
    rbacService := services.NewRBACService(db)

    // 初始化RBAC系统
    if err := rbac.InitializeRBAC(rbacService); err != nil {
        log.Printf("RBAC初始化失败: %v", err)
    }

    // 初始化控制器
    rbacController := controllers.NewRBACController(rbacService)

    // 初始化路由
    r := gin.Default()

    // 使用RBAC中间件
    r.Use(middleware.RBACMiddleware(rbacService))

    // API路由
    api := r.Group("/api/v1")
    {
        // 角色管理
        roles := api.Group("/roles")
        roles.Use(middleware.RequirePermission("role", "read"))
        {
            roles.GET("", rbacController.GetRoles)
            roles.POST("", middleware.RequirePermission("role", "create"), rbacController.CreateRole)
        }

        // 权限管理
        permissions := api.Group("/permissions")
        permissions.Use(middleware.RequirePermission("permission", "read"))
        {
            permissions.POST("", middleware.RequirePermission("permission", "create"), rbacController.CreatePermission)
        }

        // 用户角色管理
        users := api.Group("/users")
        users.Use(middleware.RequirePermission("user", "read"))
        {
            users.POST("/:user_id/roles", middleware.RequirePermission("user", "update"), rbacController.AssignRoleToUser)
            users.DELETE("/:user_id/roles/:role_id", middleware.RequirePermission("user", "update"), rbacController.RevokeRoleFromUser)
            users.GET("/:user_id/permissions", rbacController.GetUserPermissions)
            users.GET("/:user_id/check-permission", rbacController.CheckPermission)
        }

        // 角色权限管理
        rolePermissions := api.Group("/roles/:role_id/permissions")
        rolePermissions.Use(middleware.RequirePermission("role", "update"))
        {
            rolePermissions.POST("", rbacController.AssignPermissionToRole)
        }

        // 管理员专用接口
        admin := api.Group("/admin")
        admin.Use(middleware.RequireRole("admin"))
        {
            admin.GET("/dashboard", func(c *gin.Context) {
                c.JSON(200, gin.H{"message": "管理员仪表板"})
            })
        }

        // 超级管理员专用接口
        superAdmin := api.Group("/super-admin")
        superAdmin.Use(middleware.RequireRole("super_admin"))
        {
            superAdmin.GET("/system", func(c *gin.Context) {
                c.JSON(200, gin.H{"message": "系统管理"})
            })
        }

        // 动态权限控制的接口
        dynamic := api.Group("/dynamic")
        dynamic.Use(middleware.DynamicPermissionMiddleware())
        {
            dynamic.GET("/data", func(c *gin.Context) {
                c.JSON(200, gin.H{"message": "数据"})
            })
            dynamic.POST("/data", func(c *gin.Context) {
                c.JSON(200, gin.H{"message": "数据已创建"})
            })
        }
    }

    log.Println("RBAC服务器启动在 :8080")
    r.Run(":8080")
}

RBAC 最佳实践 #

1. 权限设计原则 #

  • 最小权限原则:用户只获得完成工作所需的最小权限
  • 职责分离:敏感操作需要多个角色协作完成
  • 权限继承:合理设计角色层次结构
  • 动态权限:支持运行时权限检查和调整

2. 性能优化 #

  • 权限缓存:缓存用户权限信息
  • 批量检查:一次性检查多个权限
  • 索引优化:为关联表创建合适的索引
  • 懒加载:按需加载权限信息

3. 安全考虑 #

  • 权限审计:记录权限变更日志
  • 定期清理:清理过期的权限分配
  • 权限验证:在关键操作前再次验证权限
  • 防止提权:防止用户获得超出预期的权限

RBAC 提供了一种灵活而强大的权限管理机制,通过合理的设计和实现,可以满足复杂企业应用的权限控制需求。