【问题标题】:Django: Authentication credentials were not providedDjango:未提供身份验证凭据
【发布时间】:2019-05-25 18:13:10
【问题描述】:

我已经收集了十几个关于这个主题的类似 SO 帖子,并按照我理解的最佳方式实施了他们的解决方案,但它们对我没有用。 为什么我收到此错误 detail: "Authentication credentials were not provided." 在使用 AJAX 补丁请求访问我的 Django Rest Framework 端点后? 感谢您的帮助!

一些细节

  • 标题告诉我“状态代码:401 未授权”
  • 我在我的 localHost 开发服务器 (Postgres) 上
  • 在此应用程序内的其他应用程序上运行的任何其他 django 表单或 ajax(Get 和 Posts)请求都没有出现此错误。
  • 这是我第一次尝试 PATCH 请求
  • 最终,一旦这个 Ajax 补丁请求有效,我只想将 bookid 添加到 api.BookGroup 模型中的 ManyToManyField books 字段
  • 我已尝试遵循类似帖子中的建议,这些帖子建议调整 settings.py 以允许正确的身份验证和权限方法。
  • 参考the DRF documentation,我还将权限类更​​改为permission_classes = (IsAuthenticated,),如果我在发出请求时已登录(是的,我肯定已登录),则应该允许补丁请求
  • ajax 标头中的表单数据显示我正确地传递了 CSRF 令牌和正确的变量:

    csrfmiddlewaretoken: UjGnVfQTfcmkZKtWjI0m89zlAJqR0wMmUVdh1T1JaiCdyRe2TiW3LPWt
    bookid: 1
    bookgroupid: 71
    

AJAX

function AddToBookGroup(bookgroupid,bookid){
 $.ajax({
    type: "PATCH",
    url: '/api/bookgroups/'+bookgroupid+'/',
    data: {
        csrfmiddlewaretoken: window.CSRF_TOKEN,
        bookid: bookid,
        bookgroupid: bookgroupid
        }, 
    success: function(data){
        console.log( 'success, server says '+data);  
    }
 });
}

URLS.py

from django.urls import path, include
from django.conf.urls import url
from . import views
from django.conf import settings
from django.conf.urls.static import static

urlpatterns = [
    path('', include(router.urls)),
    url(r'bookgroups/\d+/$', views.BookGroupUpdateSet.as_view()),
] + static(settings.MEDIA_URL, document_root=settings.MEDIA_ROOT)

VIEWS.py

from rest_framework.generics import ListAPIView, DestroyAPIView, UpdateAPIView, RetrieveAPIView
from rest_framework.authentication import TokenAuthentication, SessionAuthentication, BasicAuthentication
from rest_framework.authtoken.serializers import AuthTokenSerializer
from rest_framework.authtoken.views import ObtainAuthToken
from rest_framework.permissions import IsAuthenticatedOrReadOnly, IsAuthenticated
from . import serializers, models, permissions

class BookGroupUpdateSet(UpdateAPIView):
    queryset = models.BookGroup.objects.all()
    model = models.BookGroup
    serializer_class = serializers.BookGroupUpdateSerializer

    def patch(self, request, pk=None):
        permission_classes = (IsAuthenticated,)
        authentication_classes = (TokenAuthentication,)
        bookid = request.Patch['bookid']
        bookgroupid = request.Patch['bookgroupid']
        print("...Print stuff...")

SETTINGS.py

INSTALLED_APPS = [
    'django.contrib.admin',
    'django.contrib.auth',
    'django.contrib.contenttypes',
    'django.contrib.sessions',
    'django.contrib.messages',
    'django.contrib.staticfiles',
    'authenticate',
    'api',
    'rest_framework',
    'rest_framework.authtoken',
]

AUTH_USER_MODEL = "api.UserProfile"

REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': (
   'rest_framework.authentication.TokenAuthentication',
   'rest_framework.authentication.SessionAuthentication',
),
'DEFAULT_PERMISSION_CLASSES': (
    # 'rest_framework.permissions.AllowAny',  # I've tried this too, same results
    'rest_framework.permissions.IsAuthenticated',
)
}

【问题讨论】:

  • 由于您已将TokenAuthentication 定义为身份验证类,因此您必须在 HTTP 标头中包含令牌。
  • @Borut 我该怎么做?我尝试将headers: {'Authorization': 'Token '+window.CSRF_TOKEN}, 添加到我的 ajax 中(在 url:... 和 data:... 之间,在这种情况下,我收到一个新错误“无效令牌。”(该令牌是从 django 模板标签中提取的,使用window.CSRF_TOKEN = "{{ csrf_token }}"; - 我也尝试添加 headers: {'X_CSRF_TOKEN': window.CSRF_TOKEN}, 和其他变体,但继续收到“未提供身份验证凭据。”错误
  • 您必须添加 API 令牌,而不是 CSRF 令牌。如果您查看与authentication 相关的 DRF 文档,您就会明白我的意思。看起来你想要 SessionAuthentication 在这里,但我不能确定,更改或更新 authentication_classes 以包含 SessionAuthentication 可能会在这里解决你的问题。令牌身份验证是无状态的,它没有会话,并且用户使用从 API 登录端点收到的令牌进行身份验证。
  • 我尝试在视图中将authentication_classes = (TokenAuthentication,) 换成authentication_classes = (SessionAuthentication,),但我得到了同样的错误。奇怪的是,我觉得我已经完全模仿了我在这个应用程序中为其他 ajax Post 调用工作的设置,而且我不必通过标头身份验证或上面示例中列出的任何内容。我不确定它只是导致问题的 PATCH 请求类型还是什么。
  • 好吧,身份验证和权限类变量应该是类变量,并且在方法中声明它们不会做任何事情,但是由于您在设置中设置了默认值,所以它不能与有效的会话,特别是如果这在其他地方有效,唯一的区别是 PATCH 方法。把它改成 PUT 看看会发生什么。

标签: python ajax django authentication django-rest-framework


【解决方案1】:

一旦您的 API 视图需要身份验证才能访问,您需要向请求的标头提供 Authorization 标头: Authorization: Token <token>

那么,你如何获得这个 Token?根据 DRF 文档,您需要为数据库中的每个用户创建一个令牌。因此,每当创建新用户时,您都必须手动执行,或者您可以通过导入和使用来使用 DRF Token 身份验证视图:

from rest_framework.authtoken.views import ObtainAuthToken

但我建议你使用 django-rest-auth 应用程序,它使 DRF 中的 Token 身份验证过程更容易。 https://django-rest-auth.readthedocs.io/en/latest/

【讨论】:

    【解决方案2】:

    使用 Django Rest Framework 视图,您不使用 CSRF 令牌,而是使用自定义 DRF 令牌(这就是 rest_framework.authtoken 的用途)。当您创建一个新用户时,您必须创建他的令牌,如下所示:

    def create(self, validated_data):
        from rest_framework.authtoken.models import Token
    
        try:
            user = models.User.objects.get(email=validated_data.get('email'))
        except User.DoesNotExist:
            user = models.User.objects.create(**validated_data)
    
            user.set_password(user.password)
            user.save()
            Token.objects.create(user=user) # -------> Token creation
    
            return user
        else:
            raise CustomValidation('eMail already in use', 'email', status_code=status.HTTP_409_CONFLICT)
    

    然后,您必须为用户获取令牌,并将其发送到带有键名Authorization 和值Token <token> 的标头中。

    【讨论】:

      猜你喜欢
      • 2019-07-29
      • 2019-06-11
      • 2017-11-22
      • 2015-05-16
      • 2019-04-29
      • 2015-01-10
      • 1970-01-01
      • 1970-01-01
      • 2015-02-05
      相关资源
      最近更新 更多