Django Rest 框架 JWT
Django Rest Framework JWT
我正在使用 Django Rest Framework 为我的应用程序构建 API,并希望实施 DjangoRestFramework-JWT 以进行令牌身份验证。这些步骤看起来很简单,但是当我测试端点时,出现 500 错误。终端输出一大堆 html 表示没有提供 csrf_token。代码和错误如下。非常感谢您的帮助。
curl -X POST -d "username=admin&password=123abc" http://127.0.0.1:8000/api/token/auth/
CSRF 错误
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<meta name="robots" content="NONE,NOARCHIVE">
<title>403 Forbidden</title>
</head>
<body>
<div id="summary">
<h1>Forbidden <span>(403)</span></h1>
<p>CSRF verification failed. Request aborted.</p>
<p>You are seeing this message because this site requires a CSRF cookie when submitting forms. This cookie is required for security reasons, to ensure that your browser is not being hijacked by third parties.</p>
<p>If you have configured your browser to disable cookies, please re-enable them, at least for this site, or for 'same-origin' requests.</p>
</div>
<div id="info">
<h2>Help</h2>
<p>Reason given for failure:</p>
<pre>CSRF cookie not set.</pre>
<p>In general, this can occur when there is a genuine Cross Site Request Forgery, or when <a href="https://docs.djangoproject.com/en/1.8/ref/csrf/">Django's CSRF mechanism</a> has not been used correctly. For POST forms, you need to ensure:</p>
<ul>
<li>Your browser is accepting cookies.</li>
<li>The view function passes a <code>request</code> to the template's <a href="https://docs.djangoproject.com/en/dev/topics/templates/#django.template.backends.base.Template.render"><code>render</code></a> method.</li>
<li>In the template, there is a <code>{% csrf_token %}</code> template tag inside each POST form that targets an internal URL.</li>
<li>If you are not using <code>CsrfViewMiddleware</code>, then you must use <code>csrf_protect</code> on any views that use the <code>csrf_token</code> template tag, as well as those that accept the POST data.</li>
</ul>
<p>You're seeing the help section of this page because you have <code>DEBUG = True</code> in your Django settings file. Change that to <code>False</code>, and only the initial error message will be displayed. </p>
<p>You can customize this page using the CSRF_FAILURE_VIEW setting.</p>
</div>
</body>
</html>
Settings.py
INSTALLED_APPS = (
...
'rest_framework',
...
)
REST_FRAMEWORK = {
'DEFAULT_PERMISSION_CLASSES': (
'rest_framework.permissions.IsAuthenticated',
),
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework.authentication.SessionAuthentication',
'rest_framework.authentication.BasicAuthentication',
'rest_framework_jwt.authentication.JSONWebTokenAuthentication',
),
}
JWT_AUTH = {
'JWT_RESPONSE_PAYLOAD_HANDLER':
'app.utils.jwt_response_payload_handler',
'JWT_EXPIRATION_DELTA': datetime.timedelta(seconds=30000),
}
全球Urls.py
urlpatterns = patterns(
...
url(r'^api/auth/token/$', 'rest_framework_jwt.views.obtain_jwt_token'),
url(r'^api/auth/', include('rest_framework.urls', namespace='rest_framework')),
url(r'^api/', include(router.urls)),
)
您收到此错误是因为 DRF 设置中定义了 SessionAuthentication
class。
DRF 的 SessionAuthentication
使用 Django 的 session 框架进行身份验证,需要检查 CSRF。 DRF 对经过身份验证的用户强制执行 CSRF 检查。这意味着只有经过身份验证的请求才需要 CSRF 令牌,匿名请求可以在没有 CSRF 令牌的情况下发送。
现在您正在从经过身份验证的用户发出请求,并且根据 settings.py
文件中 DEFAULT_AUTHENTICATION_CLASSES
中定义的顺序,首先调用 SessionAuthentication
。它检查请求是否来自经过身份验证的用户,如果是,则它必须在请求 headers 中设置 CSRF
令牌。由于您没有在请求中发送 CSRF Token
,因此 returns 出错。
您需要在 headers 中传递 CSRF 令牌,同时发出请求。您可以通过 --header/-H
选项来做到这一点。
--header "X-CSRFToken: {token_value}" # using '--header'
-H "X-CSRFToken: {token_value}" # using '-H'
您可以将请求更改为:
curl --header "X-CSRFToken: {token_value}" -X POST -d "username=admin&password=123abc" http://127.0.0.1:8000/api/token/auth/
另一种方法:
还有另一个选项,您可以在其中创建自定义 Session 身份验证 class,它不会对经过身份验证的用户强制执行此 CSRF 检查。
下面的 SessionCsrfExemptAuthentication
class 不会对经过身份验证的用户强制执行 CSRF 令牌检查。
from rest_framework.authentication import SessionAuthentication
class SessionCsrfExemptAuthentication(SessionAuthentication):
def enforce_csrf(self, request):
return # To not perform the csrf check previously happening
然后您可以在您的设置中定义此身份验证 class:
'DEFAULT_AUTHENTICATION_CLASSES': (
# Replace DRF session authentication class with our custom authentication class
'rest_framework.authentication.SessionCsrfExemptAuthentication',
'rest_framework.authentication.BasicAuthentication',
'rest_framework_jwt.authentication.JSONWebTokenAuthentication',
),
我正在使用 Django Rest Framework 为我的应用程序构建 API,并希望实施 DjangoRestFramework-JWT 以进行令牌身份验证。这些步骤看起来很简单,但是当我测试端点时,出现 500 错误。终端输出一大堆 html 表示没有提供 csrf_token。代码和错误如下。非常感谢您的帮助。
curl -X POST -d "username=admin&password=123abc" http://127.0.0.1:8000/api/token/auth/
CSRF 错误
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8">
<meta name="robots" content="NONE,NOARCHIVE">
<title>403 Forbidden</title>
</head>
<body>
<div id="summary">
<h1>Forbidden <span>(403)</span></h1>
<p>CSRF verification failed. Request aborted.</p>
<p>You are seeing this message because this site requires a CSRF cookie when submitting forms. This cookie is required for security reasons, to ensure that your browser is not being hijacked by third parties.</p>
<p>If you have configured your browser to disable cookies, please re-enable them, at least for this site, or for 'same-origin' requests.</p>
</div>
<div id="info">
<h2>Help</h2>
<p>Reason given for failure:</p>
<pre>CSRF cookie not set.</pre>
<p>In general, this can occur when there is a genuine Cross Site Request Forgery, or when <a href="https://docs.djangoproject.com/en/1.8/ref/csrf/">Django's CSRF mechanism</a> has not been used correctly. For POST forms, you need to ensure:</p>
<ul>
<li>Your browser is accepting cookies.</li>
<li>The view function passes a <code>request</code> to the template's <a href="https://docs.djangoproject.com/en/dev/topics/templates/#django.template.backends.base.Template.render"><code>render</code></a> method.</li>
<li>In the template, there is a <code>{% csrf_token %}</code> template tag inside each POST form that targets an internal URL.</li>
<li>If you are not using <code>CsrfViewMiddleware</code>, then you must use <code>csrf_protect</code> on any views that use the <code>csrf_token</code> template tag, as well as those that accept the POST data.</li>
</ul>
<p>You're seeing the help section of this page because you have <code>DEBUG = True</code> in your Django settings file. Change that to <code>False</code>, and only the initial error message will be displayed. </p>
<p>You can customize this page using the CSRF_FAILURE_VIEW setting.</p>
</div>
</body>
</html>
Settings.py
INSTALLED_APPS = (
...
'rest_framework',
...
)
REST_FRAMEWORK = {
'DEFAULT_PERMISSION_CLASSES': (
'rest_framework.permissions.IsAuthenticated',
),
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework.authentication.SessionAuthentication',
'rest_framework.authentication.BasicAuthentication',
'rest_framework_jwt.authentication.JSONWebTokenAuthentication',
),
}
JWT_AUTH = {
'JWT_RESPONSE_PAYLOAD_HANDLER':
'app.utils.jwt_response_payload_handler',
'JWT_EXPIRATION_DELTA': datetime.timedelta(seconds=30000),
}
全球Urls.py
urlpatterns = patterns(
...
url(r'^api/auth/token/$', 'rest_framework_jwt.views.obtain_jwt_token'),
url(r'^api/auth/', include('rest_framework.urls', namespace='rest_framework')),
url(r'^api/', include(router.urls)),
)
您收到此错误是因为 DRF 设置中定义了 SessionAuthentication
class。
DRF 的 SessionAuthentication
使用 Django 的 session 框架进行身份验证,需要检查 CSRF。 DRF 对经过身份验证的用户强制执行 CSRF 检查。这意味着只有经过身份验证的请求才需要 CSRF 令牌,匿名请求可以在没有 CSRF 令牌的情况下发送。
现在您正在从经过身份验证的用户发出请求,并且根据 settings.py
文件中 DEFAULT_AUTHENTICATION_CLASSES
中定义的顺序,首先调用 SessionAuthentication
。它检查请求是否来自经过身份验证的用户,如果是,则它必须在请求 headers 中设置 CSRF
令牌。由于您没有在请求中发送 CSRF Token
,因此 returns 出错。
您需要在 headers 中传递 CSRF 令牌,同时发出请求。您可以通过 --header/-H
选项来做到这一点。
--header "X-CSRFToken: {token_value}" # using '--header'
-H "X-CSRFToken: {token_value}" # using '-H'
您可以将请求更改为:
curl --header "X-CSRFToken: {token_value}" -X POST -d "username=admin&password=123abc" http://127.0.0.1:8000/api/token/auth/
另一种方法:
还有另一个选项,您可以在其中创建自定义 Session 身份验证 class,它不会对经过身份验证的用户强制执行此 CSRF 检查。
下面的SessionCsrfExemptAuthentication
class 不会对经过身份验证的用户强制执行 CSRF 令牌检查。
from rest_framework.authentication import SessionAuthentication
class SessionCsrfExemptAuthentication(SessionAuthentication):
def enforce_csrf(self, request):
return # To not perform the csrf check previously happening
然后您可以在您的设置中定义此身份验证 class:
'DEFAULT_AUTHENTICATION_CLASSES': (
# Replace DRF session authentication class with our custom authentication class
'rest_framework.authentication.SessionCsrfExemptAuthentication',
'rest_framework.authentication.BasicAuthentication',
'rest_framework_jwt.authentication.JSONWebTokenAuthentication',
),