DRF-spectacular自定义权限致端点不显示的解决方案咨询
问题:DRF-spectacular中自定义权限导致端点未显示在Schema中,且需授权后可见
- 配置drf-spectacular并给视图集加装饰器后,对应端点未出现在Schema文档里
- 排查确认是自定义权限拦截导致:将权限改为
AllowAny时,Schema能正常显示端点。两个自定义权限逻辑分别是:- 校验请求头是否包含
header-x - 通过QuerySet查询数据库做权限校验
- 校验请求头是否包含
- 需求:不想删除现有权限,希望实现两种效果之一——要么让Swagger生成Schema时忽略权限校验,要么仅在用户授权后才显示这些受保护的端点
- 已尝试的操作:
- 修改DRF-spectacular配置未找到有效方法
- 将
SERVE_PUBLIC设为True能看到所有端点,但未授权状态下也可查看,不符合需求
- 当前DRF-spectacular配置:
"TITLE": "My API", "DESCRIPTION": "My description", "SERVE_INCLUDE_SCHEMA": False, 'SERVE_PUBLIC': False,
解决方案
1. 让Schema生成时跳过权限校验
drf-spectacular生成Schema时会模拟请求走权限校验流程,你可以给自定义权限类加个判断,让它在Schema生成阶段直接放行:
from rest_framework.permissions import BasePermission from drf_spectacular.utils import is_schema_request # 校验header-x的权限类 class HeaderXPermission(BasePermission): def has_permission(self, request, view): # 识别是否是Schema生成请求,是的话直接返回True if is_schema_request(request): return True # 原有的权限校验逻辑 return 'header-x' in request.headers # 基于QuerySet的权限类 class QuerySetCheckPermission(BasePermission): def has_permission(self, request, view): if is_schema_request(request): return True # 原有的数据库查询校验逻辑 return YourModel.objects.filter(user=request.user).exists()
这样Schema生成时会跳过权限校验,正常收录端点,而实际业务请求时权限逻辑依然生效。
2. 实现「授权后才显示端点」的效果
要做到未授权用户看不到受保护端点,授权后正常显示,需要结合Swagger认证和自定义过滤逻辑:
- 首先确保Swagger配置了正确的认证方式(比如TokenAuth、SessionAuth),让用户能在Swagger页面完成授权
- 保持
SERVE_PUBLIC=False,然后在settings.py的SPECTACULAR_SETTINGS中添加自定义过滤后端:
自定义过滤后端示例:"SPECTACULAR_SETTINGS": { # 其他原有配置... 'SERVE_PUBLIC': False, 'FILTER_BACKENDS': [ 'drf_spectacular.backends.SpectacularFilterBackend', # 自定义过滤后端,控制不同权限用户能看到的端点 'your_project.utils.CustomPermissionFilterBackend', ], }from drf_spectacular.backends import SpectacularFilterBackend class CustomPermissionFilterBackend(SpectacularFilterBackend): def filter(self, schema, request, public): # 用户未认证时,过滤掉受保护的端点 if not request.user.is_authenticated: filtered_paths = {} for path, path_data in schema['paths'].items(): # 这里可以根据实际情况判断,比如按路径前缀、视图权限类筛选 # 示例:只保留非/protected/开头的端点 if not path.startswith('/protected/'): filtered_paths[path] = path_data schema['paths'] = filtered_paths return schema
3. 临时方案:用装饰器指定Schema生成时的权限
如果不想修改权限类,可以在视图集上用@extend_schema装饰器,单独给Schema生成阶段指定AllowAny权限:
from drf_spectacular.utils import extend_schema from rest_framework.permissions import AllowAny @extend_schema(permission_classes=[AllowAny]) class YourProtectedViewSet(viewsets.ModelViewSet): # 实际请求用的权限类 permission_classes = [HeaderXPermission, QuerySetCheckPermission] # 其他视图集配置...
这种方式下,Schema生成会用装饰器指定的AllowAny,而实际业务请求依然走视图集本身的权限校验。
内容的提问来源于stack exchange,提问作者Ronczo
相关产品推荐
相关产品推荐

