如何在drf-yasg生成的Django REST API文档中自动添加权限信息?
以下是几种无需手动编写,自动将权限信息注入生成的API文档的实现思路:
扩展SchemaGenerator自动提取权限
继承drf_yasg的OpenAPISchemaGenerator,重写get_operation方法,在生成每个接口的Schema操作对象时,自动提取视图的权限类、关联的Permission模型信息,将其追加到接口描述中。
示例代码:from drf_yasg.generators import OpenAPISchemaGenerator from rest_framework.permissions import BasePermission from django.contrib.auth.models import Permission class PermissionAwareSchemaGenerator(OpenAPISchemaGenerator): def get_operation(self, path, method, view): operation = super().get_operation(path, method, view) permission_classes = getattr(view, 'permission_classes', []) permission_notes = [] for perm_cls in permission_classes: if issubclass(perm_cls, BasePermission): # 处理DjangoModelPermissions这类带权限映射的内置权限 if hasattr(perm_cls, 'perms_map'): required_perms = perm_cls.perms_map.get(method.lower(), []) for perm_codename in required_perms: app_label, codename = perm_codename.split('.') try: perm_obj = Permission.objects.get(codename=codename, content_type__app_label=app_label) permission_notes.append(f"{perm_obj.name} (权限编码: {perm_codename})") except Permission.DoesNotExist: permission_notes.append(f"未定义权限: {perm_codename}") else: # 处理自定义权限类,直接读取类名和文档字符串 perm_desc = perm_cls.__doc__.strip() if perm_cls.__doc__ else "无描述" permission_notes.append(f"自定义权限[{perm_cls.__name__}]: {perm_desc}") if permission_notes: desc_prefix = operation.get('description', '') operation['description'] = f"{desc_prefix}\n\n**所需权限:**\n- {chr(10)}- ".join(permission_notes) if desc_prefix else f"**所需权限:**\n- {chr(10)}- ".join(permission_notes) return operation最后在项目settings中配置drf_yasg使用这个生成器:
SWAGGER_SETTINGS = { 'DEFAULT_GENERATOR_CLASS': 'your_project.path.to.PermissionAwareSchemaGenerator', # 其他配置... }自定义SwaggerAutoSchema实现视图级权限注入
如果需要更细粒度的控制,可以自定义SwaggerAutoSchema,重写get_operation方法实现权限信息注入,然后在指定视图或全局配置使用该类。
示例:from drf_yasg.inspectors import SwaggerAutoSchema class PermissionSwaggerSchema(SwaggerAutoSchema): def get_operation(self, operation_keys=None): operation = super().get_operation(operation_keys) view = self.view # 权限提取逻辑和上面一致,省略重复代码 permission_classes = getattr(view, 'permission_classes', []) permission_notes = [] for perm_cls in permission_classes: if issubclass(perm_cls, BasePermission): if hasattr(perm_cls, 'perms_map'): required_perms = perm_cls.perms_map.get(self.method.lower(), []) for perm_codename in required_perms: app_label, codename = perm_codename.split('.') try: perm_obj = Permission.objects.get(codename=codename, content_type__app_label=app_label) permission_notes.append(f"{perm_obj.name} (权限编码: {perm_codename})") except Permission.DoesNotExist: permission_notes.append(f"未定义权限: {perm_codename}") else: perm_desc = perm_cls.__doc__.strip() if perm_cls.__doc__ else "无描述" permission_notes.append(f"自定义权限[{perm_cls.__name__}]: {perm_desc}") if permission_notes: operation['description'] = (operation.get('description', '') + "\n\n**权限要求:**\n- " + "\n- ".join(permission_notes)).strip() return operation使用时可以在视图类中指定:
class YourAPIView(APIView): swagger_schema_class = PermissionSwaggerSchema permission_classes = [IsAuthenticated, DjangoModelPermissions] # 视图逻辑...也可以全局配置默认的schema类。
给权限类添加元数据简化提取
针对自定义权限类,可以预先添加描述性元数据,避免在生成Schema时做复杂的数据库查询或逻辑解析:class ArticleEditPermission(BasePermission): permission_meta = { 'name': '编辑文章权限', 'codename': 'article.edit_article', 'description': '允许用户修改已发布的文章' } def has_permission(self, request, view): return request.user.has_perm(self.permission_meta['codename'])之后在Schema生成逻辑中,直接读取
perm_cls.permission_meta的内容即可,更高效且易维护。适配OpenAPI Security规范
如果需要符合OpenAPI的安全认证标准,可以在Schema中定义securitySchemes(如JWT、Session认证),并给每个接口的operation添加security字段,关联对应的权限范围。比如在自定义Generator中添加:def get_schema(self, request=None, public=False): schema = super().get_schema(request, public) # 添加securitySchemes定义 schema['components']['securitySchemes'] = { "BearerAuth": { "type": "http", "scheme": "bearer", "bearerFormat": "JWT" } } return schema然后在
get_operation中给需要权限的接口添加:operation['security'] = [{"BearerAuth": []}]这样文档会清晰展示接口的认证方式和权限要求。
内容的提问来源于stack exchange,提问作者Shad

