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

求助:Django Rest Framework函数视图缓存致权限类失效

Django DRF 函数视图缓存与权限类冲突的修复方案

问题根源

你遇到的问题是装饰器执行顺序导致的:@cache_page放在最外层时,会直接缓存权限验证通过后的完整响应。后续请求会直接返回缓存结果,完全跳过了@permission_classes和api_view的权限校验逻辑,导致权限规则失效。

修复方法

方法1:调整装饰器执行顺序(推荐)

将@cache_page移到权限相关装饰器的后面,让每次请求先经过权限验证,验证通过后才会读取缓存或生成新的响应缓存。

修改后的代码:

@api_view(['GET'])
@permission_classes((APIKeyPermission,))
@cache_page(3600)
def function_based_view(request): 
    # function-based view code here...
  • 原理:装饰器的执行顺序是从下到上(靠近函数的先执行),现在权限验证会优先于缓存逻辑执行,只有权限通过的请求才会触发缓存操作。
  • 优缺点:实现最简单,完全保证权限校验不被跳过;唯一的小代价是每次请求都要执行权限验证,但权限校验的性能开销通常远低于视图业务逻辑的开销,对整体性能影响极小。

方法2:自定义缓存键,包含权限标识

如果希望保留缓存的同时,让不同权限的请求拥有独立缓存,可以自定义缓存键生成函数,将权限相关信息(如API Key的哈希值)加入缓存键中。

示例代码:

import hashlib

def permission_based_cache_key(request, *args, **kwargs):
    # 从请求头获取API Key(根据你的实际权限类逻辑调整)
    api_key = request.META.get('HTTP_X_API_KEY', '')
    # 对API Key做哈希处理,避免敏感信息直接暴露在缓存键中
    hashed_key = hashlib.sha256(api_key.encode()).hexdigest()
    # 生成包含权限标识的缓存键
    return f"fbv_cache_{hashed_key}_{request.path}"

@cache_page(3600, key_func=permission_based_cache_key)
@api_view(['GET'])
@permission_classes((APIKeyPermission,))
def function_based_view(request): 
    # function-based view code here...
  • 原理:不同权限的请求会生成不同的缓存键,缓存内容相互隔离,同时权限验证仍会在缓存之前执行。
  • 优缺点:可以缓存不同权限用户的响应,减少重复计算;但需要额外处理缓存键的生成逻辑,且要注意敏感信息的安全处理(比如哈希API Key)。

方法3:使用自定义中间件前置权限验证

如果需要更全局的控制,可以编写一个中间件,在Django的缓存中间件之前执行权限验证,确保所有请求先过权限关,再触发缓存逻辑。

示例中间件:

from django.http import HttpResponseForbidden
from rest_framework.permissions import APIKeyPermission

class PermissionBeforeCacheMiddleware:
    def __init__(self, get_response):
        self.get_response = get_response

    def __call__(self, request):
        # 仅对目标视图的GET请求做权限验证
        if request.path == "/your-view-path/" and request.method == "GET":
            permission = APIKeyPermission()
            if not permission.has_permission(request, None):
                return HttpResponseForbidden("Permission denied")
        response = self.get_response(request)
        return response

然后将这个中间件添加到settings.py的MIDDLEWARE列表中,且要放在django.middleware.cache.UpdateCacheMiddleware之前。

  • 优缺点:适合全局统一处理;但需要精确匹配目标视图,逻辑相对复杂,不推荐用于单个视图的场景。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.23 21:13:22