权限控制
VEF Framework 提供了灵活的权限控制机制,支持基于令牌的权限验证。
权限令牌
定义 API 权限
go
// Set permission for prebuilt API
apis.NewFindPageApi[models.User, payloads.UserSearch]().
WithPermission("user:read")
apis.NewCreateApi[models.User, payloads.UserParams]().
WithPermission("user:create")
apis.NewUpdateApi[models.User, payloads.UserParams]().
WithPermission("user:update")
apis.NewDeleteApi[models.User]().
WithPermission("user:delete")自定义 API 权限
go
// Register API with permission
resource.RegisterApiWithPermission(
"reset_password",
"user:reset_password",
resource.ResetPassword,
)权限命名约定
推荐使用 {module}:{action} 格式:
| 权限令牌 | 说明 |
|---|---|
user:read | 查看用户 |
user:create | 创建用户 |
user:update | 更新用户 |
user:delete | 删除用户 |
user:export | 导出用户 |
order:approve | 审批订单 |
权限检查
自动权限检查
配置了权限的 API 会自动进行权限检查:
go
// This API requires "user:read" permission
apis.NewFindPageApi[models.User, payloads.UserSearch]().
WithPermission("user:read")
// Request without permission will receive 403 Forbidden手动权限检查
go
func (r *UserResource) AdminOperation(ctx fiber.Ctx) error {
currentUser := contextx.GetCurrentUser(ctx)
// Check single permission
if !currentUser.HasPermission("admin:manage") {
return api.Forbidden(ctx, "Permission denied")
}
// Check any of permissions
if !currentUser.HasAnyPermission("admin:manage", "super:admin") {
return api.Forbidden(ctx, "Permission denied")
}
// Check all permissions
if !currentUser.HasAllPermissions("user:read", "user:update") {
return api.Forbidden(ctx, "Permission denied")
}
return api.Success(ctx, nil)
}权限加载
实现 PermissionLoader
go
package auth
import (
"github.com/ilxqx/vef-framework-go/auth"
"github.com/ilxqx/vef-framework-go/orm"
)
type PermissionLoaderImpl struct{}
func NewPermissionLoader() auth.PermissionLoader {
return &PermissionLoaderImpl{}
}
// LoadPermissions loads permissions for user
func (l *PermissionLoaderImpl) LoadPermissions(userId string, roleIds []string) ([]string, error) {
var permissions []string
// Load role permissions
err := orm.DB().
Table("role_permissions rp").
Select("DISTINCT p.token").
Joins("JOIN permissions p ON p.id = rp.permission_id").
Where("rp.role_id IN ?", roleIds).
Pluck("p.token", &permissions).Error
if err != nil {
return nil, err
}
// Load user-specific permissions
var userPermissions []string
orm.DB().
Table("user_permissions up").
Select("p.token").
Joins("JOIN permissions p ON p.id = up.permission_id").
Where("up.user_id = ?", userId).
Pluck("p.token", &userPermissions)
// Merge permissions
permissionSet := make(map[string]bool)
for _, p := range permissions {
permissionSet[p] = true
}
for _, p := range userPermissions {
permissionSet[p] = true
}
result := make([]string, 0, len(permissionSet))
for p := range permissionSet {
result = append(result, p)
}
return result, nil
}权限缓存
配置权限缓存
yaml
# config.yaml
auth:
permission:
cacheEnabled: true
cacheTTL: 300 # seconds清除权限缓存
go
import "github.com/ilxqx/vef-framework-go/auth"
// Clear cache for specific user
auth.ClearPermissionCache(userId)
// Clear all permission cache
auth.ClearAllPermissionCache()动态权限
基于条件的权限
go
func (r *OrderResource) ApproveOrder(ctx fiber.Ctx, params struct {
OrderId string `json:"orderId" validate:"required"`
}) error {
currentUser := contextx.GetCurrentUser(ctx)
// Load order
var order models.Order
if err := orm.DB().First(&order, "id = ?", params.OrderId).Error; err != nil {
return api.NotFound(ctx, "Order not found")
}
// Check dynamic permission based on order amount
if order.Amount > 10000 {
if !currentUser.HasPermission("order:approve:high") {
return api.Forbidden(ctx, "Cannot approve high-value orders")
}
} else {
if !currentUser.HasPermission("order:approve") {
return api.Forbidden(ctx, "Permission denied")
}
}
// Approve order
order.Status = "approved"
order.ApprovedBy = currentUser.Id
order.ApprovedAt = time.Now()
if err := orm.DB().Save(&order).Error; err != nil {
return api.Error(ctx, "Failed to approve order")
}
return api.Success(ctx, order)
}权限继承
实现权限继承
go
// Permission hierarchy
// admin:* -> admin:user:*, admin:order:*, admin:system:*
// admin:user:* -> admin:user:read, admin:user:create, admin:user:update, admin:user:delete
func (u *UserInfo) HasPermission(permission string) bool {
// Check exact match
for _, p := range u.Permissions {
if p == permission {
return true
}
}
// Check wildcard permissions
parts := strings.Split(permission, ":")
for i := len(parts) - 1; i >= 0; i-- {
wildcardPermission := strings.Join(parts[:i], ":") + ":*"
for _, p := range u.Permissions {
if p == wildcardPermission {
return true
}
}
}
return false
}