Django Rest Framework 请求对 AllowAny 设置进行身份验证

Posted

技术标签:

【中文标题】Django Rest Framework 请求对 AllowAny 设置进行身份验证【英文标题】:Django Rest Framework requesting authentication on AllowAny setting 【发布时间】:2015-06-02 12:53:21 【问题描述】:

我为应用创建了一个JWT-Authorised 后端。登录、注销、令牌检索和刷新都可以正常工作,并且符合预期。我今天早上添加了一个注册视图,它会抛出通常的"detail": "Authentication credentials were not provided. 错误,你会期望未经身份验证的请求,因为这是默认值(见下文)。

但是,由于这是一个注册端点,我不希望它只允许授权请求。 (使用有效令牌进行检查后,当您提供身份验证时,视图的其余部分按预期工作。)查看DRF docs 的权限部分,我认为使用 AllowAny 的 permission_classes 包装器可以在这里工作,但它没有吨。

我错过了什么?我觉得 permission_classes 装饰器应该覆盖“IsAuthenticated”的默认设置?

我正在通过 curl 在 localhost 上进行测试:

curl -X POST -H "Content-Type: application/json" -d '"email":"boba@athingy09876.com", "first_name": "boba", "last_name": "fett" "password":"xyz"' http://localhost:8000/account/register/

视图是:

@permission_classes(AllowAny)
@api_view(['POST'])
def register_user(request):
    from django.contrib.auth.models import User
    from rest_framework_jwt.views import obtain_jwt_token
    if request.user.is_authenticated():
        return Response ("already_registered": "User with that username has already registered", status=status.HTTP_701_ALREADY_REGISTERED)
    data = request.data

    user, created = User.objects.get_or_create(username=data["email"],
                                               email=data["email"],
                                               first_name=data["first_name"],
                                               last_name=data["last_name"],
                                               password=data["password"])
    if created:
        token = obtain_jwt_token(data["email"],data["password"] )
        return Response ("token": token, status=status.HTTP_200_OK)
    else:
        return Response ("already_registered": "User with that username has already registered", status=status.HTTP_701_ALREADY_REGISTERED)

settings.py 中的权限是:

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',
    ),

相关问题: Django Rest Framework - Authentication credentials were not provided - 我认为默认权限是正确的,我只是想在这种情况下覆盖它们。

Django Rest Framework - DELETE ajax call failure due to incorrect CSFR token - CSRF 未被用作基于 JWT 的身份验证。

Django: Rest Framework authenticate header - Apache 特定问题(目前仍在 devserver localhost 上)

Django Rest Framework Authentication credentials were not provided - 尚未回答!

【问题讨论】:

我的回答对你有用吗? 嘿!我还没有机会实现它,但它看起来不错 - 我明天会在赏金到期之前实现它。 :) 抱歉耽搁了! 完全不清楚为什么这个问题被否决了,顺便说一句 - 如果这个问题有问题,请告诉我,这不像是一个半生不熟、未经研究的问题。跨度> 【参考方案1】:

您使用@permission_classes 禁用了权限,但这只是“身份验证和授权”的“授权”部分。您需要禁用the authentication handlers 以及使用@authentication_classes 以停止接收401/403 错误。

【讨论】:

对不起,我不太明白你的意思。从阅读中可以看出,当身份验证按预期失败时,它应该在 request.user 处提供 AnonymousUser - 但根据权限的东西,这无关紧要,@permission_classes(AllowAny) 应该允许不受限制的访问。无论如何,我尝试使用 @authentication_classes((SessionAuthentication, BasicAuthentication)) 无济于事,并且在 restframework.authentication 中看不到任何涵盖此用例的内容 - 我是否需要为此扩展基类?似乎有点矫枉过正......(就像,我很确定我只是不明白) 我也进入并设置了REST_FRAMEWORK = 'DEFAULT_PERMISSION_CLASSES': [], 'DEFAULT_AUTHENTICATION_CLASSES': [], ,这似乎可行,但现在我必须将所有其他函数包装在显式装饰器中,而不是使用默认行为,这似乎有点倒退?当然有一种(更清晰的?)禁用身份验证处理程序的方法。我已经浏览过你链接的文档好几次了,我只是没有看到。 :(【参考方案2】:

装饰器的顺序很重要。您的代码也存在一些问题。

我建议使用序列化程序,可能如下所示。如果您想使用电子邮件作为用户名,我会制作一个自定义用户模型。 Django 的默认身份验证系统的用户名字段的 max_length 为 30,人们的电子邮件地址很容易超过。

class UserSerializer(serializers.ModelSerializer):
    first_name = serializers.CharField(required=False, allow_null=True)
    last_name = serializers.CharField(required=False, allow_null=True)
    class Meta:
        model = User
        fields = ('id', 'username', 'first_name', 'last_name', 'email', 'password')

    def create(self, validated_data):
        return User.objects.create_user(**validated_data)

@api_view(['POST'])
@permission_classes([permissions.AllowAny,])
def register_user(request):
    if request.user.is_authenticated():
        return Response("already_registered": "User with that username has already registered", status=701)
    data = request.data
    serializer = UserSerializer(data=data, partial=True)
    if serializer.is_valid():
        serializer.save(username=serializer.validated_data['email'])
        token = #call the url to get your tokens, use urllib or something similar
        return Response("token": token, status=status.HTTP_201_CREATED)
    else:
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

编辑 装饰器的顺序是这样的:

@decorator
@decorator2
def func():
    print('hello world')

同装饰器(decorator2(func)))

【讨论】:

天哪。我改变了装饰器的顺序,然后繁荣,你去。我无法让序列化版本立即工作,但我明白你的意思,所以明天我会以这种方式重做,以此为起点。谢谢!我在哪里可以找到更多关于订购这样的装饰器的想法? 添加了一些关于装饰器的内容...尝试放在这里,但代码在 cmets 上看起来很可怕...

以上是关于Django Rest Framework 请求对 AllowAny 设置进行身份验证的主要内容,如果未能解决你的问题,请参考以下文章

python-django rest framework框架之解析器

django-rest-framework - POST 请求返回“方法 \"GET\" 不允许。”

django框架学习六:优化views.py文件,使用rest_framework中的APIVew和Response返回

使用 Django Rest Framework JWT 的手动令牌

django rest_framework--入门教程3

Django REST Framework 删除方法请求收到 Forbidden 403