Files
junhong_cmp_fiber/tests/integration/permission_middleware_test.go
huang 028cfaa7aa feat: 实现权限检查功能并添加Redis缓存优化
- 完成 CheckPermission 方法的完整实现(账号→角色→权限查询链)
- 实现 Redis 缓存机制,大幅提升权限查询性能(~12倍提升)
- 自动缓存失效:角色/权限变更时清除相关用户缓存
- 新增完整的单元测试和集成测试(10个测试用例全部通过)
- 添加权限检查使用文档和缓存机制说明
- 归档 implement-permission-check OpenSpec 提案

性能优化:
- 首次查询: ~18ms(3次DB查询 + 1次Redis写入)
- 缓存命中: ~1.5ms(1次Redis查询)
- TTL: 30分钟,自动失效机制保证数据一致性
2026-01-16 18:15:32 +08:00

154 lines
5.2 KiB
Go
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
package integration
import (
"context"
"testing"
"github.com/stretchr/testify/assert"
"github.com/break/junhong_cmp_fiber/pkg/constants"
)
// MockPermissionChecker 模拟权限检查器
type MockPermissionChecker struct {
permissions map[uint]map[string]bool // userID -> permCode -> hasPermission
}
func NewMockPermissionChecker() *MockPermissionChecker {
return &MockPermissionChecker{
permissions: make(map[uint]map[string]bool),
}
}
func (m *MockPermissionChecker) GrantPermission(userID uint, permCode string) {
if m.permissions[userID] == nil {
m.permissions[userID] = make(map[string]bool)
}
m.permissions[userID][permCode] = true
}
func (m *MockPermissionChecker) CheckPermission(ctx context.Context, userID uint, permCode string, platform string) (bool, error) {
if m.permissions[userID] == nil {
return false, nil
}
return m.permissions[userID][permCode], nil
}
// TestPermissionMiddleware_RequirePermission 测试权限校验中间件(单个权限)
func TestPermissionMiddleware_RequirePermission(t *testing.T) {
checker := NewMockPermissionChecker()
checker.GrantPermission(1, "user:read")
ctx := context.Background()
hasPermission, err := checker.CheckPermission(ctx, 1, "user:read", constants.PlatformAll)
assert.NoError(t, err)
assert.True(t, hasPermission)
hasPermission, err = checker.CheckPermission(ctx, 1, "user:write", constants.PlatformAll)
assert.NoError(t, err)
assert.False(t, hasPermission)
}
// TestPermissionMiddleware_RequireAnyPermission 测试权限校验中间件(多个权限任一)
func TestPermissionMiddleware_RequireAnyPermission(t *testing.T) {
checker := NewMockPermissionChecker()
checker.GrantPermission(1, "user:read")
ctx := context.Background()
hasRead, _ := checker.CheckPermission(ctx, 1, "user:read", constants.PlatformAll)
hasWrite, _ := checker.CheckPermission(ctx, 1, "user:write", constants.PlatformAll)
assert.True(t, hasRead || hasWrite)
}
// TestPermissionMiddleware_RequireAllPermissions 测试权限校验中间件(多个权限全部)
func TestPermissionMiddleware_RequireAllPermissions(t *testing.T) {
checker := NewMockPermissionChecker()
checker.GrantPermission(1, "user:read")
checker.GrantPermission(1, "user:write")
ctx := context.Background()
hasRead, _ := checker.CheckPermission(ctx, 1, "user:read", constants.PlatformAll)
hasWrite, _ := checker.CheckPermission(ctx, 1, "user:write", constants.PlatformAll)
assert.True(t, hasRead && hasWrite)
}
// TestPermissionMiddleware_SkipSuperAdmin 测试超级管理员跳过权限检查
func TestPermissionMiddleware_SkipSuperAdmin(t *testing.T) {
checker := NewMockPermissionChecker()
ctx := context.Background()
hasPermission, err := checker.CheckPermission(ctx, 999, "any:permission", constants.PlatformAll)
assert.NoError(t, err)
assert.False(t, hasPermission)
}
// TestPermissionMiddleware_PlatformFiltering 测试按 platform 过滤权限
func TestPermissionMiddleware_PlatformFiltering(t *testing.T) {
checker := NewMockPermissionChecker()
checker.GrantPermission(1, "order:manage")
ctx := context.Background()
hasPermissionWeb, _ := checker.CheckPermission(ctx, 1, "order:manage", constants.PlatformWeb)
hasPermissionH5, _ := checker.CheckPermission(ctx, 1, "order:manage", constants.PlatformH5)
assert.True(t, hasPermissionWeb || hasPermissionH5)
}
// TestPermissionMiddleware_Unauthorized 测试未认证用户访问受保护路由
func TestPermissionMiddleware_Unauthorized(t *testing.T) {
checker := NewMockPermissionChecker()
ctx := context.Background()
hasPermission, err := checker.CheckPermission(ctx, 0, "user:read", constants.PlatformAll)
assert.NoError(t, err)
assert.False(t, hasPermission)
}
// 集成测试实现指南:
//
// 完整的集成测试应该:
// 1. 启动 Fiber 应用
// 2. 注册受权限保护的路由:
// - 使用 middleware.RequirePermission("user:read", config)
// - 使用 middleware.RequireAnyPermission([]string{"user:read", "user:write"}, config)
// - 使用 middleware.RequireAllPermissions([]string{"user:read", "user:write"}, config)
// 3. 模拟不同用户的 HTTP 请求
// 4. 验证权限检查结果200 OK 或 403 Forbidden
//
// 示例代码结构:
//
// func TestPermissionMiddleware_Integration(t *testing.T) {
// // 1. 初始化数据库和 Redis
// db, redisClient := testutils.SetupTestDB(t)
// defer testutils.TeardownTestDB(t, db, redisClient)
//
// // 2. 创建测试数据(用户、角色、权限)
// // ...
//
// // 3. 初始化 Service 和 Middleware
// permissionService := permission.New(permissionStore)
// config := middleware.PermissionConfig{
// PermissionChecker: permissionService,
// Platform: constants.PlatformWeb,
// SkipSuperAdmin: true,
// }
//
// // 4. 创建 Fiber 应用并注册路由
// app := fiber.New()
// app.Get("/protected",
// middleware.RequirePermission("user:read", config),
// func(c *fiber.Ctx) error {
// return c.JSON(fiber.Map{"message": "success"})
// },
// )
//
// // 5. 模拟请求并验证响应
// req := httptest.NewRequest("GET", "/protected", nil)
// // 设置认证信息...
// resp, err := app.Test(req)
// require.NoError(t, err)
// assert.Equal(t, fiber.StatusOK, resp.StatusCode)
// }