认证组件
用于判断用户是否登录
简单使用
# 1.创建一个任意名字的py文件
# 2.导入认证类
from rest_framework.authentication import BaseAuthentication
# 3.写一个类继承它并且重写authenticate方法
class LoginAuth(BaseAuthentication):
def authenticate(self, request):
token = request.META.get('HTTP_TOKEN')
user_token = models.User_token.objects.filter(token=token).first()
if user_token:
return user_token.user, token
else:
raise AuthenticationFailed('请先登录')
# 4.在views.py导入这个自己写的类
from .authentication import LoginAuth
# 5.局部使用 在视图类下写authentication_classes属性,并且将自己写的认证类加到这个列表
class UserOperation():
authentication_classes = [LoginAuth]
# 6.全局使用 在settings.py文件下配置REST_FRAMEWORK
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES':[
'app01.auth.Login_authentication'
]
}
# 7.局部禁用 在某个想要禁用的视图类下定义列表为空
authentication_classes = []
认证类源码解析
在视图类执行as_view()时会先到dispath()封装一个新的request
dispatch
def dispatch(self, request, *args, **kwargs):
self.args = args
self.kwargs = kwargs
# 通过initialize_request封装新的request
request = self.initialize_request(request, *args, **kwargs)
self.request = request
self.headers = self.default_response_headers # deprecate?
initialize_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
)
get_authenticators
def get_authenticators(self):
# 会通过遍历这个authentication_classes可迭代对象来以此调用里面的认证类对象
# 这就是为什么我们需要在视图类里面定义这么一个列表或者元组
return [auth() for auth in self.authentication_classes]
回到dispatch方法里面,查看三大认证操作
initial
def initial(self, request, *args, **kwargs):
# 这三行代码进行了三大认证,点到perform_authentication里面看一看
self.perform_authentication(request)
self.check_permissions(request)
self.check_throttles(request)
perform_authentication
def perform_authentication(self, request):
# 就这么一行代码 看不出什么
# 要想知道user是什么 从哪里来,就要去看看这个request的类是这么定义的
# 当前这个request是经过Request包装过的新的request
# 所以接下来去看看Request()这个类
request.user
Request
类
发现user是一个包装成属性的方法
@property
def user(self):
# 如果当前request没有_user这个属性,就执行_authenticate方法
if not hasattr(self, '_user'):
# 做了一个异常捕获
with wrap_attributeerrors():
self._authenticate()
# 最后是返回了一个_user 说明_authenticate一定对_user赋值了
return self._user
# 所以接下来点到_authenticate方法看一看
_authenticate
方法
def _authenticate(self):
# authenticators是实例化request对象时传入的参数,
# 他是一个列表,列表里面是一个个认证类的实例
for authenticator in self.authenticators:
try:
# 如果没有东西就会被异常捕获
user_auth_tuple = authenticator.authenticate(self)
except exceptions.APIException:
self._not_authenticated()
raise
# 如果user_auth_tuple非空,就说明认证类里面的authenticate方法返回东西了
if user_auth_tuple is not None:
# 把认证类实例赋值给_authenticator
self._authenticator = authenticator
# 分别把值赋给user和auth
# 也就是此时 request.user 就有值了
self.user, self.auth = user_auth_tuple
return
# 如果没有报错,且没有返回元组,那么就执行了这么个玩意
self._not_authenticated()
# 下面点进_not_authenticated
_not_authenticated
def _not_authenticated(self):
self._authenticator = None
# 如果配置文件配置了这个对象
if api_settings.UNAUTHENTICATED_USER:
# 就会执行某个函数,然后把返回值赋给user
# 这个函数点进去看就会发现时执行了__str__方法然后返回了个字符串AnonymousUser
# 也就是匿名用户的意思
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
手动设置user
@user.setter
def user(self, value):
# 这段源码解释了
# 当手动设置user对象的时候
# 还会把老的request.user 也设置成当前设置的user对象
self._user = value
self._request.user = value
总结
当请求来的时候会执行dispach方法initialize_request方法包装新的request对象
Request会传入authenticators=self.get_authenticators(),如果你定义了序列化类,就会实例化这个类,把这个对象加到一个列表里,如果没有就不会触发校验
这时候新的request对象已经生成好了,然后视图类对象会执行initial
方法,这里面会触发perform_authentication
方法进行认证,
这个方法会执行request.user,然后执行Request类的_authenticate
方法,这里就会根据你的序列化类的authenticate
方法的返回值给request.user和request.auth赋值。