You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何使用In Memory Caching优化用户权限授权性能

用内存缓存优化权限校验性能

改动步骤

  1. 注入内存缓存服务
    在UserPolicy类中引入IMemoryCache,用于管理内存中的权限数据。

  2. 更新构造函数
    修改构造函数,接收注入的IMemoryCache实例。

  3. 实现缓存逻辑
    权限校验时优先从缓存读取用户权限列表;缓存未命中时,从数据库加载数据并写入缓存,后续请求直接复用缓存数据完成校验。

修改后的完整代码

private readonly IHttpContextAccessor _contextAccessor;
private readonly ApplicationDbContext _dbContext;
private readonly IMemoryCache _memoryCache;

public UserPolicy(IHttpContextAccessor contextAccessor, ApplicationDbContext dbContext, IMemoryCache memoryCache)
{
    _contextAccessor = contextAccessor;
    _dbContext = dbContext;
    _memoryCache = memoryCache;
}

protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, UserPolicyRequirement requirement)
{
    var request = _contextAccessor.HttpContext?.Request;
    if (request == null)
    {
        context.Fail();
        return Task.CompletedTask;
    }

    string actionName = request.RouteValues["action"].ToString();
    string controllerName = request.RouteValues["controller"].ToString();
    var token = request.Headers[HeaderNames.Authorization].ToString();

    if (!string.IsNullOrEmpty(token))
    {
        var handler = new JwtSecurityTokenHandler();
        var jwtToken = handler.ReadJwtToken(token.Replace("Bearer ", "")) as JwtSecurityToken;
        if (jwtToken == null)
        {
            context.Fail();
            return Task.CompletedTask;
        }

        var userId = jwtToken.Claims.FirstOrDefault(c => c.Type == "userId")?.Value;
        if (string.IsNullOrEmpty(userId))
        {
            context.Fail();
            return Task.CompletedTask;
        }

        // 定义缓存键,确保每个用户的权限独立存储
        var cacheKey = $"UserPermissions_{userId}";
        
        // 尝试从缓存获取权限列表,不存在则从数据库加载
        if (!_memoryCache.TryGetValue(cacheKey, out List<UserAccessAction> userPermissions))
        {
            // 从数据库查询用户所有权限
            userPermissions = _dbContext.userAccessActions
                .Where(a => a.UserId == userId)
                .ToList();

            // 设置缓存选项:滑动过期30分钟(无访问自动清理)+ 绝对过期2小时(定期刷新)
            var cacheOptions = new MemoryCacheEntryOptions()
                .SetSlidingExpiration(TimeSpan.FromMinutes(30))
                .SetAbsoluteExpiration(TimeSpan.FromHours(2));

            // 将权限列表写入缓存
            _memoryCache.Set(cacheKey, userPermissions, cacheOptions);
        }

        // 用缓存中的权限列表完成校验
        if (userPermissions.Any(a => a.ActionName == actionName && a.ControllName == controllerName))
        {
            // 用户拥有当前接口权限
            context.Succeed(requirement);
        }
        else
        {
            // 用户无当前接口权限
            context.Fail();
        }
    }
    else
    {
        // 未携带token,直接拒绝访问
        context.Fail();
    }

    return Task.CompletedTask;
}

关键说明

  • 缓存键设计:以UserPermissions_{userId}作为缓存键,避免不同用户的权限数据互相干扰。
  • 过期策略:同时配置滑动过期和绝对过期,既清理长期不活跃用户的缓存,也定期刷新缓存,避免权限变更后数据不一致。
  • 空值防护:新增对request、jwtToken、userId的空值判断,防止空引用异常。

内容的提问来源于stack exchange,提问作者sadegh

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.23 23:02:37