feat: backend core - auth, user, role, permission, device, webhook, monitoring, cache, repository, service, middleware, API handlers
This commit is contained in:
156
internal/api/middleware/rbac.go
Normal file
156
internal/api/middleware/rbac.go
Normal file
@@ -0,0 +1,156 @@
|
||||
package middleware
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
)
|
||||
|
||||
// contextKey 上下文键常量
|
||||
const (
|
||||
ContextKeyRoleCodes = "role_codes"
|
||||
ContextKeyPermissionCodes = "permission_codes"
|
||||
)
|
||||
|
||||
// RequirePermission 要求用户拥有指定权限之一(OR 逻辑)
|
||||
// 适用于需要单个或多选权限校验的路由
|
||||
func RequirePermission(codes ...string) gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
if !hasAnyPermission(c, codes) {
|
||||
c.JSON(http.StatusForbidden, gin.H{
|
||||
"code": 403,
|
||||
"message": "权限不足",
|
||||
})
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
c.Next()
|
||||
}
|
||||
}
|
||||
|
||||
// RequireAllPermissions 要求用户拥有所有指定权限(AND 逻辑)
|
||||
func RequireAllPermissions(codes ...string) gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
if !hasAllPermissions(c, codes) {
|
||||
c.JSON(http.StatusForbidden, gin.H{
|
||||
"code": 403,
|
||||
"message": "权限不足,需要所有指定权限",
|
||||
})
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
c.Next()
|
||||
}
|
||||
}
|
||||
|
||||
// RequireRole 要求用户拥有指定角色之一(OR 逻辑)
|
||||
func RequireRole(codes ...string) gin.HandlerFunc {
|
||||
return func(c *gin.Context) {
|
||||
if !hasAnyRole(c, codes) {
|
||||
c.JSON(http.StatusForbidden, gin.H{
|
||||
"code": 403,
|
||||
"message": "权限不足,角色受限",
|
||||
})
|
||||
c.Abort()
|
||||
return
|
||||
}
|
||||
c.Next()
|
||||
}
|
||||
}
|
||||
|
||||
// RequireAnyPermission RequirePermission 的别名,语义更清晰
|
||||
func RequireAnyPermission(codes ...string) gin.HandlerFunc {
|
||||
return RequirePermission(codes...)
|
||||
}
|
||||
|
||||
// AdminOnly 仅限 admin 角色
|
||||
func AdminOnly() gin.HandlerFunc {
|
||||
return RequireRole("admin")
|
||||
}
|
||||
|
||||
// GetRoleCodes 从 Context 获取当前用户角色代码列表
|
||||
func GetRoleCodes(c *gin.Context) []string {
|
||||
val, exists := c.Get(ContextKeyRoleCodes)
|
||||
if !exists {
|
||||
return nil
|
||||
}
|
||||
if codes, ok := val.([]string); ok {
|
||||
return codes
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// GetPermissionCodes 从 Context 获取当前用户权限代码列表
|
||||
func GetPermissionCodes(c *gin.Context) []string {
|
||||
val, exists := c.Get(ContextKeyPermissionCodes)
|
||||
if !exists {
|
||||
return nil
|
||||
}
|
||||
if codes, ok := val.([]string); ok {
|
||||
return codes
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// IsAdmin 判断当前用户是否为 admin
|
||||
func IsAdmin(c *gin.Context) bool {
|
||||
return hasAnyRole(c, []string{"admin"})
|
||||
}
|
||||
|
||||
// hasAnyPermission 判断用户是否拥有任意一个权限
|
||||
func hasAnyPermission(c *gin.Context, codes []string) bool {
|
||||
// admin 角色拥有所有权限
|
||||
if IsAdmin(c) {
|
||||
return true
|
||||
}
|
||||
permCodes := GetPermissionCodes(c)
|
||||
if len(permCodes) == 0 {
|
||||
return false
|
||||
}
|
||||
permSet := toSet(permCodes)
|
||||
for _, code := range codes {
|
||||
if _, ok := permSet[code]; ok {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// hasAllPermissions 判断用户是否拥有所有权限
|
||||
func hasAllPermissions(c *gin.Context, codes []string) bool {
|
||||
if IsAdmin(c) {
|
||||
return true
|
||||
}
|
||||
permCodes := GetPermissionCodes(c)
|
||||
permSet := toSet(permCodes)
|
||||
for _, code := range codes {
|
||||
if _, ok := permSet[code]; !ok {
|
||||
return false
|
||||
}
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
// hasAnyRole 判断用户是否拥有任意一个角色
|
||||
func hasAnyRole(c *gin.Context, codes []string) bool {
|
||||
roleCodes := GetRoleCodes(c)
|
||||
if len(roleCodes) == 0 {
|
||||
return false
|
||||
}
|
||||
roleSet := toSet(roleCodes)
|
||||
for _, code := range codes {
|
||||
if _, ok := roleSet[code]; ok {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// toSet 将字符串切片转换为 map 集合
|
||||
func toSet(items []string) map[string]struct{} {
|
||||
s := make(map[string]struct{}, len(items))
|
||||
for _, item := range items {
|
||||
s[item] = struct{}{}
|
||||
}
|
||||
return s
|
||||
}
|
||||
Reference in New Issue
Block a user