我正在使用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。
您可以通过包含启用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.
我建议你使用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)