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

Django如何自动为接口添加Cognito认证 仅豁免指定接口

解决方案

报错根因说明

  • 方案1中间件报错:DRF的Response对象需要经过DRF的渲染流程处理才能返回,中间件直接返回Response时还没设置accepted_renderer属性,触发断言错误。
  • 方案2自定义认证类报错:DRF的BaseAuthentication子类的authenticate方法只允许返回(用户实例, 认证信息)的元组,或者抛出认证异常,不能直接返回Response对象,返回Response会导致DRF后续处理逻辑异常。

正确实现方案(DRF原生认证+权限体系,兼容所有视图类型)

步骤1:修正自定义Cognito认证类

authenticator.py代码如下:

from rest_framework.authentication import BaseAuthentication
from rest_framework.exceptions import AuthenticationFailed
from datetime import datetime
from django.contrib.auth.models import AnonymousUser
from cheers.core.api.jwt_helpers import decode_cognito_jwt

class CognitoAuthentication(BaseAuthentication):
    def authenticate(self, request):
        auth = request.headers.get("Authorization", None)
        if not auth:
            raise AuthenticationFailed('Authorization header expected')

        parts = auth.split()
        if parts[0].lower() != "bearer":
            raise AuthenticationFailed('Authorization header must start with bearer')
        elif len(parts) == 1:
            raise AuthenticationFailed('Token not found')
        elif len(parts) > 2:
            raise AuthenticationFailed('Authorization header must be Bearer token')

        token = parts[1]
        try:
            res = decode_cognito_jwt(token)
            expiration = datetime.utcfromtimestamp(res['exp'])
            current_utc = datetime.utcnow()

            if current_utc > expiration:
                raise AuthenticationFailed(f'current time:{current_utc} is after expiration:{expiration}, Please login again')
        except Exception:
            raise AuthenticationFailed("Invalid JWT")
        
        # 认证通过返回用户和认证信息,可根据业务替换为实际用户实例
        return AnonymousUser(), None

步骤2:实现豁免认证装饰器@donotauth

新建decorators.py:

def donotauth(view_func):
    """标记视图不需要认证"""
    view_func.donotauth = True
    return view_func

步骤3:实现配套权限类

新建permissions.py:

from rest_framework.permissions import BasePermission

class IsAuthenticatedUnlessDonotAuth(BasePermission):
    def has_permission(self, request, view):
        # 视图如果被@donotauth标记,直接放行
        if getattr(view, 'donotauth', False) or getattr(getattr(view, 'view_class', None), 'donotauth', False):
            return True
        # 否则检查是否通过认证
        return request.user is not None

步骤4:全局配置DRF设置

修改settings.py:

REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': (
        'cheers.utils.authenticator.CognitoAuthentication',
    ),
    'DEFAULT_PERMISSION_CLASSES': (
        'cheers.utils.permissions.IsAuthenticatedUnlessDonotAuth',
    ),
}

步骤5:使用示例

函数视图豁免认证:

@donotauth
@api_view(['GET'])
@swagger_auto_schema(
    operation_description="Get <count> most recent posts by category"
)
def get_most_recent_posts_by_category(request, category, count):
    return Response(status=status.HTTP_200_OK)

类视图豁免所有方法认证:

from django.utils.decorators import method_decorator

@method_decorator(donotauth, name='dispatch')
class PublicView(APIView):
    def get(self, request):
        return Response()

类视图豁免单个方法认证:

class MixedView(APIView):
    @method_decorator(donotauth)
    def get(self, request):
        # 该方法无需认证
        return Response()
    
    def post(self, request):
        # 该方法需要认证
        return Response()

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.02 04:15:03