Django REST Framework系列教程(6)——认证详解与Token认证
目次什么是认证(Authentication)?
DRF自带认证方案
如何在DRF中设置认证方案?
设置默认的全局认证方案
在基于类的视图(CBV)中使用
在基于函数的视图中使用
如何自定义认证方案?
示例
前后端分离时为何推荐token认证?
如何使用TokenAuthentication
自定义Token返复书息
在前篇的开发博客API案例中,我们详细先容了如何在DRF中使用权限,并通过自定义权限实现了只有颠末身份验证的用户可以创建文章而且只有文章的所有者可以更新和删除文章资源。然而前篇文章中我们使用了Django默认的基于session的认证方式,实际前后端分离开发项目中背景更多采用的是token(令牌认证)。本文将详细先容如何在DRF中使用不同的认证方案,并重点先容如何使用DRF自带的token认证。
什么是认证(Authentication)?
身份验证是将传入的请求对象(request)与一组标识根据(比方用户名+密码或者令牌token)相干联的机制。REST framework 提供了一些开箱即用的身份验证方案,而且还答应你实现自定义方案。
DRF的每个认证方案实际上是一个类。你可以在视图中使用一个或多个认证方案类。REST framework 将尝试使用列表中的每个类举行身份验证,并使用成功完成验证的第一个类的返回的元组设置 request.user 和request.auth。
用户通过认证后request.user返回Django的User实例,否则返回AnonymousUser的实例。request.auth通常为None。假如使用token认证,request.auth可以包含认证过的token。
注:认证一般发生在权限校验之前。
DRF自带认证方案
Django REST Framework提供了如下几种认证方案:
[*]Session认证SessionAuthentication类:此认证方案使用Django的默认session后端举行身份验证。当客户端发送登录请求通过验证后,Django通过session将用户信息存储在服务器中保持用户的请求状态。Session身份验证明用于与你的网站在相同的Session情况中运行的AJAX客户端 (注:这也是Session认证的最大弊端)。
[*]根本认证BasicAuthentication类:此认证方案使用HTTP 根本认证,针对用户的用户名和密码举行认证。使用这种方式后欣赏器会跳出登录框让用户输入用户名和密码认证。根本认证通常只实用于测试。
[*]远程认证RemoteUserAuthentication类:此认证方案为用户名不存在的用户自动创建用户实例。这个很少用,具体见文档。
[*]Token认证TokenAuthentication类:该认证方案是DRF提供的使用简单的基于Token的HTTP认证方案。当客户端发送登录请求时,服务器便会天生一个Token并将此Token返回给客户端,作为客户端举行请求的一个标识以后客户端只需带上这个Token前来请求数据即可,无需再次带上用户名和密码。背面我们会详细先容如何使用这种认证方案。
注意:假如你在生产情况下使用BasicAuthentication和TokenAuthentication认证,你必须确保你的API仅在https可用。
如何在DRF中设置认证方案?
设置默认的全局认证方案
# settings.py
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework.authentication.BasicAuthentication',
'rest_framework.authentication.SessionAuthentication',
)}
在基于类的视图(CBV)中使用
from rest_framework.authentication import SessionAuthentication, BasicAuthentication
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from rest_framework.views import APIView
class ExampleView(APIView):
authentication_classes = (SessionAuthentication, BasicAuthentication)
permission_classes = (IsAuthenticated,)
在基于函数的视图中使用
from rest_framework.decorators import api_view, authentication_classes, permission_classes
@api_view(['GET'])
@authentication_classes((SessionAuthentication, BasicAuthentication))
@permission_classes((IsAuthenticated,))
def example_view(request, format=None):
content = {
'user': unicode(request.user),# `django.contrib.auth.User` 实例。
'auth': unicode(request.auth),# None
}
return Response(content)
如何自定义认证方案?
要实现自定义的认证方案,首先要继承BaseAuthentication类而且重写.authenticate(self, request)方法。假如认证成功,该方法应返回(user, auth)的二元元组,否则返回None。
在某些情况下,你可能不想返回None,而是希望从.authenticate()方法抛出AuthenticationFailed非常。通常你应该采取的方法是:
[*]假如不尝试验证,返回None。还将检查任何其他正在使用的身份验证方案。
[*]假如尝试验证但失败,则抛出AuthenticationFailed非常。无论任何权限检查也不检查任何其他身份验证方案,立即返回错误相应。
你也可以重写.authenticate_header(self, request)方法。假如实现该方法,则应返回一个字符串,该字符串将用作HTTP 401 Unauthorized相应中的WWW-Authenticate头的值。假如.authenticate_header()方法未被重写,则认证方案将在未验证的请求被拒绝访问时返回HTTP 403 Forbidden相应。
示例
以下示例将以自定义请求标头中名称为’X_USERNAME’提供的用户名作为用户对任何传入请求举行身份验证,别的类似自定义认证需求比如支持用户同时按用户名或email举行验证。
from django.contrib.auth.models import User
from rest_framework import authentication
from rest_framework import exceptions
class ExampleAuthentication(authentication.BaseAuthentication):
def authenticate(self, request):
username = request.META.get('X_USERNAME')
if not username:
return None
try:
user = User.objects.get(username=username)
except User.DoesNotExist:
raise exceptions.AuthenticationFailed('No such user')
return (user, None)
前后端分离时为何推荐token认证?
[*]Token无需存储降低服务器本钱,session是将用户信息存储在服务器中的,当用户量增大时服务器的压力也会随着增大。
[*]防御CSRF跨站伪造请求攻击,session是基于cookie举行用户识别的, cookie假如被截获,用户信息就轻易泄露。
[*]扩展性强,session必要存储无法共享,当搭建了多个服务器时其他服务器无法获取到session中的验证数据用户无法验证成功。Token可以实现服务器间共享,这样不管那里都可以访问到。
[*]Token可以减轻服务器的压力,淘汰频繁的查询数据库。
[*]支持跨域访问, 实用于移动平台应用
如何使用TokenAuthentication
DRF自带的TokenAuthentication方案可以实现根本的token认证,整个流程如下:
首先,你必要将修改settings.py, 加入如下app。
INSTALLED_APPS = (
...
'rest_framework.authtoken'
)
其次,你必要为你的用户天生令牌(token)。假如你希望在创建用户时自动天生token,你可以借助Django的信号(signals)实现,如下所示:
from django.conf import settings
from django.db.models.signals import post_save
from django.dispatch import receiver
from rest_framework.authtoken.models import Token
@receiver(post_save, sender=settings.AUTH_USER_MODEL)
def create_auth_token(sender, instance=None, created=False, **kwargs):
if created:
Token.objects.create(user=instance)
假如你已经创建了一些用户,则可以打开shell为所有现有用户天生令牌,如下所示:
from django.contrib.auth.models import User
from rest_framework.authtoken.models import Token
for user in User.objects.all():
Token.objects.get_or_create(user=user)
你还可以在admin.py中给用户创建token,如下所示:
from rest_framework.authtoken.admin import TokenAdmin
TokenAdmin.raw_id_fields = ['user']
从3.6.4起,你还可以使用如下命令为一个指定用户新建或重置token。
./manage.py drf_create_token <username> # 新建
./manage.py drf_create_token -r <username> # 重置
接下来,你必要袒露用户获取token的url地址(API端点).
from rest_framework.authtoken import views
urlpatterns += [
url(r'^api-token-auth/', views.obtain_auth_token)]
这样每当用户使用form表单或JSON将有用的username和password字段POST提交到以上视图时,obtain_auth_token视图将返回如下JSON相应:
{ 'token' : '9944b09199c62bcf9418ad846dd0e4bbdfc6ee4b' }
客户端拿到token后可以将其存储到本地cookie或localstorage里,下次发送请求时把token包含在Authorization HTTP头即可,如下所示:
Authorization: Token 9944b09199c62bcf9418ad846dd0e4bbdfc6ee4b
你还可以通过curl工具来举行简单测试。
curl -X GET http://127.0.0.1:8000/api/example/ -H 'Authorization: Token 9944b09199c62bcf9418ad846dd0e4bbdfc6ee4b
' 自定义Token返复书息
默认的obtain_auth_token视图返回的json相应数据黑白常简单的,只有token一项。假如你希望返回更多信息,比如用户id或email,就就要通过继承ObtainAuthToken类量身定制这个视图,如下所示:
from rest_framework.authtoken.views import ObtainAuthToken
from rest_framework.authtoken.models import Token
from rest_framework.response import Response
class CustomAuthToken(ObtainAuthToken):
def post(self, request, *args, **kwargs):
serializer = self.serializer_class(data=request.data,
context={'request': request})
serializer.is_valid(raise_exception=True)
user = serializer.validated_data['user']
token, created = Token.objects.get_or_create(user=user)
return Response({
'token': token.key,
'user_id': user.pk,
'email': user.email
})
然后修改urls.py:
urlpatterns +=[
path('api-token-auth/',CustomAuthToken.as_view())]
末了一步,DRF的TokenAuthentication类会从请求头中获取Token,验证其有用性。假如token有用,返回request.user。至此,整个token的签发和验证就完成了。
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页:
[1]