Django Rest Framework中的令牌认证实现

问题描述 投票:1回答:2

我正在使用Django Rest Framework开发API后端。我最初使用会话身份验证开发它,不知道它不能用于发送到移动应用程序。在Postman中尝试用户登录时,我遇到了CSRF保护方面的问题。

现在,由于我必须转移到基于令牌的身份验证才能使其正常工作,我该如何进行呢?我想如何快速实现它。我浏览了stackoverflow上的教程和答案,但实际上无法实现这一点

令牌认证是最合适的认证方法吗?我应该使用默认提供的DRF模块还是JWT或其他一些实现?我可以仅使用令牌身份验证进行用户登录,还可以使用其他3个API的会话身份验证?

class UserLogin(APIView):
queryset = User.objects.all()
serializer_class = UserSerializer
def post(self, request, format='json'):
    username = request.POST.get('username')
    email = request.POST.get('email')
    password = request.POST.get('password')
    user = EmailBackend.authenticate(self,username = email, password = password)
    if user:
        id = user.id
        return Response(id, status=status.HTTP_201_CREATED)
    else:
        return Response("Failure", status=HTTP_400_BAD_REQUEST)

class UserRegistration(APIView):
    queryset = User.objects.all()
    serializer_class = UserSerializer
    def post(self, request, format='json'):
        serializer = UserSerializer(data=request.data)
        if serializer.is_valid():
             user = serializer.save()
             if user:
             return Response('Success', status=status.HTTP_201_CREATED)
        else:
            return Response(serializer.errors, status=HTTP_400_BAD_REQUEST)

class RecommendationQuestions(generics.ListCreateAPIView):
    def post(self, request, format = 'json'):
        """Save the post data when logging in."""
        uid = request.data['user_id']
        resp_list = MovieSerializer.provide_movie_choices(uid)
        return Response(resp_list, status=status.HTTP_400_BAD_REQUEST)

class RecommendationGenerator(generics.ListCreateAPIView):
    queryset = Ratings.objects.all()#.filter(id__in=(1,2))
    serializer_class= RatingsSerializer#(queryset,many=True)
    def post(self, request, format='json'):
        many = isinstance(request.data, list)
        serializer = RatingsSerializer(data = request.data, many = many)
        x = 0
        if serializer.is_valid():
            uid = [d['userId'] for d in serializer.data]
            resp_list = RatingsSerializer.generate_recommendations(self, uid[0])
            return Response(resp_list, status=status.HTTP_201_CREATED)
        else:
            return Response(serializer.errors,status=status.HTTP_400_BAD_REQUEST)

这是API的views.py。

python django django-rest-framework
2个回答
7
投票

令牌认证设置

您可以通过包含启用TokenAuthentication

'rest_framework.authtoken'

在INSTALLED_APPS设置(documentation)。

之后你必须运行migrate。运行迁移后,您需要为用户创建令牌。这是一个示例代码:

from django.contrib.auth.models import User
from rest_framework.authtoken.models import Token

users = User.objects.all()
for user in users:
    token, created = Token.objects.get_or_create(user=user)

你只运行一次。此外,您需要为每个新用户创建令牌。您可以使用post_save信号自动执行此操作:

from django.contrib.auth.models import User
from django.dispatch import receiver
from django.db.models.signals import post_save
from rest_framework.authtoken.models import Token

@receiver(post_save, sender=User)
def create_auth_token(sender, instance=None, created=False, **kwargs):
    if created:
        Token.objects.create(user=instance) 

此外,您必须通过包括添加配置身份验证类

'rest_framework.authentication.TokenAuthentication'

在你的设置'DEFAULT_AUTHENTICATION_CLASSES'documentation

您需要做的最后一件事是将令牌身份验证的URL添加到urls.py

from rest_framework.authtoken import views as drf_views

urlpatterns += [
    path('api-token-auth/', drf_views.obtain_auth_token)
]

基于会话的身份验证适用于使用浏览器登录API。基于令牌的身份验证是无状态的,这意味着服务器不会在服务器上存储有关客户端会话的任何状态。阅读更多关于差异here。如果您通过基于令牌的身份验证登录,则您将没有会话,并且无法通过令牌以任何其他方式访问API。

验证示例

下面是使用requests库在Python中进行令牌认证的示例代码。

# Authentication
import requests
r = requests.post(<add your token auth url here>, data={'username': 'my_username', 'password': 'my_password'})
if r.status_code == 200:
    response = r.json()
    token = response['token']
    print(token)

令牌必须用于每个其他API请求。它是通过标题发送的。

# Consume API
import requests
headers = {'Authorization': 'Token {}'.format(<your token here>)}
# Request method is either GET, POST, PUT, PATCH or DELETE
r = requests.request(method=<request method>, url=<url to api>, headers=headers)

# or you can also use
# requests.get(url=<url to api>, headers=headers) or
# requests.post(url=<url to api>, headers=headers, data=<your data>) etc.

1
投票

我建议你使用JWT,它比提供rest_framework.authtoken更安全。例如一对令牌/刷新令牌为你的主令牌设置小的到期时间。这减少了令牌被盗或损坏的可能性。在JWT令牌中,您可以存储在许多情况下非常有用的有效负载。

有一个非常好的DRF库,它实现了使用JWT和DRF的所有方面,并且它非常灵活,可以适应您的目的。

http://getblimp.github.io/django-rest-framework-jwt/

我可以仅使用令牌身份验证进行用户登录,还可以使用其他3个API的会话身份验证?

是的,你绝对可以。 APIView的每个实例都具有属性“authentication_classes”,您可以专门为所需的API设置SessionAuthentication。

例如:

class RecommendationQuestions(generics.ListCreateAPIView):
        authentication_classes = (SessionAuthentication, )

        def post(self, request, format = 'json'):
            """Save the post data when logging in."""
            uid = request.data['user_id']
            resp_list = MovieSerializer.provide_movie_choices(uid)
            return Response(resp_list, status=status.HTTP_400_BAD_REQUEST)

或者你可以使用两者

class RecommendationQuestions(generics.ListCreateAPIView):
        authentication_classes = (SessionAuthentication, JSONWebTokenAuthentication)

        def post(self, request, format = 'json'):
            """Save the post data when logging in."""
            uid = request.data['user_id']
            resp_list = MovieSerializer.provide_movie_choices(uid)
            return Response(resp_list, status=status.HTTP_400_BAD_REQUEST)
© www.soinside.com 2019 - 2024. All rights reserved.