带有 jwt 身份验证的 django rest api 要求 csrf 令牌

Posted

技术标签:

【中文标题】带有 jwt 身份验证的 django rest api 要求 csrf 令牌【英文标题】:django rest api with jwt authentication is asking for csrf token 【发布时间】:2018-06-22 16:08:10 【问题描述】:

我是 django rest api 框架的新手。我正在为其余 api 使用基于 JWT 令牌的身份验证,并具有以下设置 -

    REST_FRAMEWORK = 
    'DEFAULT_AUTHENTICATION_CLASSES': (
        'rest_framework_jwt.authentication.JSONWebTokenAuthentication',
        'rest_framework.authentication.TokenAuthentication',
        'rest_framework.authentication.BasicAuthentication',
        'rest_framework.authentication.SessionAuthentication',
    ),
    'DEFAULT_PERMISSION_CLASSES': (
        'rest_framework.permissions.IsAuthenticated',

    )


AND

JWT_AUTH = 
    'JWT_ENCODE_HANDLER':
    'rest_framework_jwt.utils.jwt_encode_handler',

    'JWT_DECODE_HANDLER':
    'rest_framework_jwt.utils.jwt_decode_handler',

    'JWT_PAYLOAD_HANDLER':
    'rest_framework_jwt.utils.jwt_payload_handler',

    'JWT_PAYLOAD_GET_USER_ID_HANDLER':
    'rest_framework_jwt.utils.jwt_get_user_id_from_payload_handler',

    'JWT_RESPONSE_PAYLOAD_HANDLER':
    'rest_framework_jwt.utils.jwt_response_payload_handler',

    'JWT_SECRET_KEY': SECRET_KEY,
    'JWT_GET_USER_SECRET_KEY': None,
    'JWT_PUBLIC_KEY': None,
    'JWT_PRIVATE_KEY': None,
    'JWT_ALGORITHM': 'HS256',
    'JWT_VERIFY': True,
    'JWT_VERIFY_EXPIRATION': True,
    'JWT_LEEWAY': 0,
    'JWT_EXPIRATION_DELTA': datetime.timedelta(seconds=300),
    'JWT_AUDIENCE': None,
    'JWT_ISSUER': None,

    'JWT_ALLOW_REFRESH': True,
    'JWT_REFRESH_EXPIRATION_DELTA': datetime.timedelta(days=7),

    'JWT_AUTH_HEADER_PREFIX': ('JWT','Bearer'),
    'JWT_AUTH_COOKIE': None,


现在基于此,我在 chrome 中使用了 postman 插件,并尝试使用以下步骤测试我的 web api 进行身份验证 -

    我使用带有凭据的 url http://127.0.0.1:8000/webs/auth-jwt/ 来获取令牌。

    我使用了 url http://127.0.0.1:8000/webs/testspsearch/ 并将步骤 1 中生成的令牌作为 Authorization Bearer 传递。这被定义为 POST 方法

但是当我这样做时,我得到了错误 -> CSRF 验证失败。请求中止。 HTTP 403 错误。

你能告诉我我在这方面做错了什么吗?

【问题讨论】:

请记住,如果您从“127.0.0.1:8000”以外的任何地方向您的 api 发送请求,则(同源策略)[en.wikipedia.org/wiki/Same_origin_policy] 将生效并阻止请求(标准 CSRF 端口)。请注意,即使是在 localhost 但在不同端口上运行的 Web 前端也会被视为不同的来源。您需要启用 CORS 才能使其正常工作,例如下面提到的 @Muhammad Hassan。 【参考方案1】:

因为您是从提供数据的同一台机器发出请求,这将(相当烦人)导致 CSRF 异常。您需要在请求中包含一个 CSRF 令牌 cookie,以表明请求正常。

所以你可以做以下两件事之一:

使端点crsf 豁免 (推荐)获取 crsf 令牌并将其作为标头附加到您的 HTTP POST 请求中

CSRF 豁免

您可以通过添加装饰器使各种端点 csrf 豁免

from django.views.decorators.csrf import csrf_exempt
class SomeView(APIView):

    @csrf_exempt
    def post(self, request):
        serializer = RegisterUserSerializer(data=request.data)

请求令牌

这有点麻烦(在我看来),因为你必须使用 javascript

// using jQuery
function getCookie(name) 
    var cookieValue = null;
    if (document.cookie && document.cookie !== '') 
        var cookies = document.cookie.split(';');
        for (var i = 0; i < cookies.length; i++) 
            var cookie = jQuery.trim(cookies[i]);
            // Does this cookie string begin with the name we want?
            if (cookie.substring(0, name.length + 1) === (name + '=')) 
                cookieValue = decodeURIComponent(cookie.substring(name.length + 1));
                break;
            
        
    
    return cookieValue;

var csrftoken = getCookie('csrftoken');

For more info check the docs

【讨论】:

【参考方案2】:

使用django-cors-middleware 允许跨源请求。步骤如下

    在已安装的应用中添加corsheaders 在中间件中添加corsheaders.middleware.CorsMiddleware。 在设置中添加CORS_ORIGIN_ALLOW_ALL = False

更多设置可见文档。

【讨论】:

以上是关于带有 jwt 身份验证的 django rest api 要求 csrf 令牌的主要内容,如果未能解决你的问题,请参考以下文章

Django Rest Framework JWT 未提供身份验证凭据

JSON:带有 django-rest-framework-json-api 和 JWT 的 API

Django Rest Framework 中的 JWT 身份验证错误“无效签名”

Django Rest Framework JWT 身份验证测试

使用 Django REST 框架进行 JWT 身份验证

Django Rest Framework 避免身份验证 JWT