单独看用法
你定义了一个类CBV,类继承自APIView,在里面赋值authentication_classes字段,字段认证类列表,这几个认证类都需要你自己定义。认证类中要实现authenticate()方法和authenticate_header()方法
认证类一般继承BaseAuthentication类,然后重写authenticate方法
authenticate方法需要返回一个元组,第一个对象为用户实例,第二个为Token实例
class Authentication1():
def authenticate(self, request):
token_obj = request._request.GET.get('token')
if not token_obj:
raise exception.AuthenticationFailed('用户认证失败')
return (token_obj.user, token_obj)
def authenticate_header(self, request):
pass
##################################
from restframework.views import APIView
class OrderView(APIView):
authentication_classes = [Authentication1, Authentication2]
def get(self, request):
pass
源码流程
- 当调用OrderView时,执行dispatch()方法,此方法将request对象做了一个封装,
request = self.initialize_request
,然后将此视图类进行初始化,最后进行根据字符串进行反射,执行对应的函数。- 我们到initialize_request方法中,看到了具体的封装信息,返回的是一个Request类型的对象,里面有原来的request,还加了许多新的属性
return Request(
request,
parsers=self.get_parsers(),
authenticators=self.get_authenticators(),
negotiator=self.get_content_negotiator(),
parser_context=parser_context
)
我们看到了authenticators = self.get_authenticators()
- 我们到get_authenticators()这个方法中看具体操作
def get_authenticators(self):
"""
Instantiates and returns the list of authenticators that this view can use.
"""
return [auth() for auth in self.authentication_classes]
他其实就是返回了一个对象列表,每一个对象都是authentication_classes列表中的认证类的实例。里面的authenticators的值也得到了,现在得到了Request对象。
- 在dispatch中,得到了Response对象,然后是初始化
视图类
,执行self.initial(),最后是执行相应的函数。
在执行初始化操作中,其他的先别看,先看self.perform_authentication(request)方法
version, scheme = self.determine_version(request, *args, **kwargs)
request.version, request.versioning_scheme = version, scheme
self.perform_authentication(request)
self.check_permissions(request)
self.check_throttles(request)
这个方法就一句,
self.user
没有return。所以我们到Request对象中看有没有user属性,request.user执行的结果就是self._authenticate方法,还是Request对象的方法。
def _authenticate(self):
"""
Attempt to authenticate the request using each authentication instance
in turn.
"""
for authenticator in self.authenticators:
try:
user_auth_tuple = authenticator.authenticate(self)
except exceptions.APIException:
self._not_authenticated()
raise
if user_auth_tuple is not None:
self._authenticator = authenticator
self.user, self.auth = user_auth_tuple
return
self._not_authenticated()
self.authenticators我们已经得到了,是一个认证类实例的列表,遍历列表,并认证类对象的authenticate()方法,返回异常,或者self.user,self.auth = (元组,且必须两个值,),这个就是自定义认证类的返回结果。
还有就是所有认证都不管,返回默认的self.user,self.auth = (匿名用户,None)
再看源码,了解全局配置
- 源码中每次调用的都会先找自己类中有没有 authentication_classes,
没有再去全局中找authentication_classes = api_settings.DEFAULT_AUTHENTICATION_CLASSES
,所以我们可以给全局设置一个值,当自己类中没有时,来全局中找。
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES':[‘app1.utils.auth.Authentication’,‘ app1.utils.auth.Authentication2’ ]
}
这样写,你的继承自APIView的所有的类都会到app1.utils下面的auth.py中找到Authentication和Authentication2进行认证,不想认证的类可以在自己类的内部定义一个空的authtication_classes = [ ] 列表。
—————————————————————————————————————其实这就是配置项,让REST_FRAMEWORK的配置项工作,设置其默认的authentication_classes为后面的类。就无需在类中定义了,访问时,用的就是修改后的默认值。
- 除了DEFAULT_AUTHENTICATION_CLASSES配置,还可以设置其他的。
renderer_classes = api_settings.DEFAULT_RENDERER_CLASSES
parser_classes = api_settings.DEFAULT_PARSER_CLASSES
authentication_classes = api_settings.DEFAULT_AUTHENTICATION_CLASSES
throttle_classes = api_settings.DEFAULT_THROTTLE_CLASSES
permission_classes = api_settings.DEFAULT_PERMISSION_CLASSES
content_negotiation_class = api_settings.DEFAULT_CONTENT_NEGOTIATION_CLASS
metadata_class = api_settings.DEFAULT_METADATA_CLASS
versioning_class = api_settings.DEFAULT_VERSIONING_CLASS
如果认证失败的话,
if api_settings.UNAUTHENTICATED_USER:
self.user = api_settings.UNAUTHENTICATED_USER()
else:
self.user = None
if api_settings.UNAUTHENTICATED_TOKEN:
self.auth = api_settings.UNAUTHENTICATED_TOKEN()
else:
self.auth = None
requesr.user = api_settings.UNAUTHENTICATED_USER()
,
request.auth = api_settings.UNAUTHENTICATED_TOKEN()
所以在配置项中
'UNAUTHENTICATED_USER':None,
# 'UNAUTHENTICATED_USER':lambda :"匿名用户",
'UNAUTHENTICATED_TOKEN':None,
设置未登录的request.user = None,和request.auth = None方便判断。
为什么要加token进行身份验证呢?
- 因为源码中APIView的view被装饰器csrf _exempt装饰,此类有csrf验证的豁免权。
所以我们要把身份验证加上
restframework中的认证类
BasicAuthentication,浏览器对你的用户名和密码进行加密,放到header中,在你的header中有加密后的用户名和密码,他会到header中取得加密的值,然后进行解密,得到用户名和密码进行验证。
梳理
梳理
:
- 创建类,继承BaseAuthentication,重写方法(其中第一个必须重写)
2.1 全局使用
在settings中添加restframework配置项
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES':[‘app1.utils.auth.Authentication’,‘ app1.utils.auth.Authentication2’ ],
'UNAUTHENTICATED_USER':None,
# 'UNAUTHENTICATED_USER':lambda :"匿名用户",
'UNAUTHENTICATED_TOKEN':None,
}
- 2 局部使用/或不使用
在创建的类中添加静态字段authentications_classses = [‘认证类路径’]或者 = []空列表
再来一遍源码流程
dispatch --> 封装了request,获取定义的认证类,然后通过列表生成式创建认证类的对象,在执行类初始化时,会调用类的performe_authencation方法,到request.user,到for循环认证类对象,并调用他的_authenticate()方法进行认证,得到三种结果,认证成功,认证失败,不进行认证。request.user = 用户名
或者None
或者匿名用户
,request.auth = token或者None
使用代码
utils.auth.py 认证类
from rest_framework.authentication import BaseAuthentication
class Authentication(BaseAuthentication):
'''自定义的认证类'''
def authenticate(self, request):
pass # 具体认证逻辑
'''
token = request._request.GET.get('token')
token_obj = model.UserToken.objects.filter(token=token).first()
if not token_obj:
:raiseexception.AuthenticationFailed('用户认证失败')
return (token_obj.user, token_obj) # 把元组的元素赋值为request.user 和 request.auth
'''
def authenticate_header(self, request):
pass
views.py 视图函数
from rest_framework.views import APIView
from utils.auth import Authentication
from django.http import JsonResponse
class OrderView(APIView):
authentication_classes = [Authentication,] # 局部引用
def get(self,request):
ret = {'code':10000,'msg':None}
try:
pass # 具体视图函数逻辑
except Exception as e:
pass # 抛出异常
return JsonResponse(ret)
settings.py 全局配置
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES':['app1.utils.auth.Authentication',],
'UNAUTHENTICATED_USER':None, # 默认匿名用户配置
# 'UNAUTHENTICATED_USER':lambda :"匿名用户", # 不如上面的好用,直接判断None
'UNAUTHENTICATED_TOKEN':None, # 默认匿名用户的auth
}
拓展
认证信息可以放在header中,request.META可以获取header中的信息
默认的认证信息为Authoriation,所以获取可以通过加上HTTP_前缀
+大写键。
request.META.get('HTTP_AUTHORIATION')