认证组件使用和源码分析
1、 基本使用
class order(APIView):
authentication_classes = [MyBaseAuthentication,]
def get(self, request, *args, **kwargs):
return Response('order')
第二种使用方法是在settings中修改REST_FRAMWORK,这里会全局引用,
REST_FRAMEWORK={
"UNAUTHENTICATED_USER": None,
#全局应用组件,如果局部有自定义的组件会用局部的
"DEFAULT_AUTHENTICATION_CLASSES":['ext.MyBaseAuthentication.MyBaseAuthentication']
}
authentication_classes = [MyBaseAuthentication,]
这一句就是使用我们定义的MyBaseAuthentication.组件
from rest_framework.authentication import BaseAuthentication
from rest_framework.exceptions import AuthenticationFailed
class MyBaseAuthentication(BaseAuthentication):
def authenticate(self, request):
#做用户认证
#1读取请求的token
#2校验合法性
#3返回值
#3.1返回元组 (11,22) 认证成功 request.user request.suth
#3.2抛出异常 认证失败
#返回none 多个认证类
#token = request._request.GET.get('token')
#query_params = _request.GET
token = request.query_params.get('token')
if token:
return('zsaa',token)
else:
# raise AuthenticationFailed('认证失败')
#自定义返回
raise AuthenticationFailed({'code':11451,'msg':'请求data'})
这里就简单的判断,传递了token就认为认证通过。
而我们定义的MyBaseAuthentication以及其他的组件
不要放在view中,全局引用会造成循环引用,未加载完就被引用了
因为首先会setting里的REST_FRAMWORK开始加载
REST_FRAMEWORK={
"UNAUTHENTICATED_USER": None,
#全局应用组件,如果局部有自定义的组件会用局部的
"DEFAULT_AUTHENTICATION_CLASSES":['views.app01.MyBaseAuthentication']
# "DEFAULT_AUTHENTICATION_CLASSES":['ext.MyBaseAuthentication.MyBaseAuthentication']
}
此时假如我们自定义的组件写在views中,我们views导入的APIView也会被加载
在APIview中又会重新加载REST_FRAMWORK就造成了循环引用。(如下图)
2、认证组件源码的剖析:
def dispatch(self, request, *args, **kwargs):
self.args = args
self.kwargs = kwargs
request = self.initialize_request(request, *args, **kwargs)
self.request = request
self.headers = self.default_response_headers # deprecate?
try:
self.initial(request, *args, **kwargs)
# Get the appropriate handler method
if request.method.lower() in self.http_method_names:
handler = getattr(self, request.method.lower(),
self.http_method_not_allowed)
else:
handler = self.http_method_not_allowed
response = handler(request, *args, **kwargs)
except Exception as exc:
response = self.handle_exception(exc)
self.response = self.finalize_response(request, response, *args, **kwargs)
return self.response
执行 as_view()时会先到dispatch中通过initialize_request封装request
def initialize_request(self, request, *args, **kwargs):
"""
Returns the initial request object.
"""
parser_context = self.get_parser_context(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()会现在我们在views里定义的类中寻找authentication_classes,如果没有则去到settings中的全局设置,并实通过auth()例化成对象,如下
def get_authenticators(self):
return [auth() for auth in self.authentication_classes]
因此,第一步self.initialize_request()返回的request里面包含了实例化我们的组件
第二步是dispatch中的
self.initial(request, *args, **kwargs)
def initial(self, request, *args, **kwargs):
"""
Runs anything that needs to occur prior to calling the method handler.
"""
self.format_kwarg = self.get_format_suffix(**kwargs)
# Perform content negotiation and store the accepted info on the request
neg = self.perform_content_negotiation(request)
request.accepted_renderer, request.accepted_media_type = neg
# Determine the API version, if versioning is in use.
version, scheme = self.determine_version(request, *args, **kwargs)
request.version, request.versioning_scheme = version, scheme
# Ensure that the incoming request is permitted
self.perform_authentication(request)
self.check_permissions(request)
self.check_throttles(request)
def perform_authentication(self, request):
request.user
这里的user在Response中,使用了@property装饰器
@property
def user(self):
if not hasattr(self, '_user'):
with wrap_attributeerrors():
self._authenticate()
return self._user
def _authenticate(self):
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()
这里的for authenticator in self.authenticators:会先去我们定义的类里面找authentication_classes,如果没有就会使用全局的authentication_classes。如果认证不通过就raise报错,通过了就将self.user和self.auth赋值
补充: drf会按顺序执行每个认证类中的authenticate函数,返回值可以有None和认证信息,比如token,当返回值未None时,就会继续执行下一个认证类,之道有返回值或执行完所有的认证类的authenticate。