Python 学习笔记(二十)--Django REST Framework之认证
1. 主要代码
APIView---》dispatch方法--》initial(self, request, *args, **kwargs) ---》有认证、权限、频率的控制代码
# Ensure that the incoming request is permitted ##认证组件:检验用户--游客、合法用户、非法用户 ##游客:代表校验通过,直接进入下一步校验(权限校验) ##合法用户:代表校验通过,用户存储在request.user中,再进行下一步校验(权限校验) ##非法用户:代表校验失败,抛出异常,返回403权限异常结果。 self.perform_authentication(request) ##权限组件:校验用户权限--必须登录、所有用户、登入只读游客自读、自定义用户角色 ##认证通过,可以进入下一步校验(频率认证) ##认证失败,报错异常,返回403权限异常结果 self.check_permissions(request) ##频率组件:限制视图接口被访问的频率次数--限制条件(IP、id、、唯一键)、频率周期时间(s、m、h)、频率次数(3/s) ##没有达到限制次数:正常访问接口 ##达到限制次数:限制时间内不能访问,限制时间到达后,可以重新访问。 self.check_throttles(request)
代码的上下文,请参考 《Python 学习笔记(十五)--Django REST Framework之Request》
2. 方法perform_authentication的定义
def perform_authentication(self, request): """ Perform authentication on the incoming request. Note that if you override this and simply 'pass', then authentication will instead be performed lazily, the first time either `request.user` or `request.auth` is accessed. """ request.user ###去Request类中去查找,方法属性user
Request类中的user()方法属性
@property def user(self): """ Returns the user associated with the current request, as authenticated by the authentication classes provided to the request. """ if not hasattr(self, '_user'): ###判断self这个对象有没有_user属性 with wrap_attributeerrors(): ##上下文管理器
## 没用户,认证出用户 self._authenticate() return self._user ##有用户,则直接返回用户
Request类中的user方法,刚开始,没有_user, 则调用_authenticate(self)
3. 调用到的基础方法
上面方法进一步调用到的基础方法
def _authenticate(self): ##进行认证 """ Attempt to authenticate the request using each authentication instance in turn. """
## 遍历拿到一个个认证器,进行认证
##self.authenticators 在视图类中配置的一堆认证类产生的认证类对象组成的 list
for authenticator in self.authenticators: try:
## 认证器(对象)调用认证方法authenticate(认证类对象self,request请求对象)
## 返回值:登录的用户与认证的信息组成的 tuple
## 该方法被try包裹,代表该方法会抛异常,抛异常代表认证失败 user_auth_tuple = authenticator.authenticate(self) ###self 是request对象 except exceptions.APIException: self._not_authenticated() raise ## 返回值的处理 if user_auth_tuple is not None: self._authenticator = authenticator
## 如果有返回值,就将 登录用户 和 登录认证 分别保存到 request.user 和 request.auth中 self.user, self.auth = user_auth_tuple return self._not_authenticated() def _not_authenticated(self): """ Set authenticator, user & authtoken representing an unauthenticated request. Defaults are None, AnonymousUser & None. """ self._authenticator = None 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
self.authenticators 是我们在视图类中配置的一个个的认证类:authentication_classes = [认证类1,认证类2....],这是认证对象的列表
4. self.authenticators 为可迭代对象;注意,此时,self 是request对象。
def __init__(self, request, parsers=None, authenticators=None,negotiator=None, parser_context=None)
可以看出,authenticators 为传入参数。再进一步判断,什么时候传入的参数呢?
是 APIView--》def dispatch(self, request, *args, **kwargs)
中的 request = self.initialize_request(request, *args, **kwargs)
# Dispatch methods 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(self)的定义如下
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=[类名]对象
读取的配置来源如下
class APIView(View): # The following policies may be set at either globally, or per-view. 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
5.重写认证类
如果重新认证类,其逻辑为: 继承BaseAuthentication,重写authenticate,认证的逻辑写在里面,认证通过,返回 self.user, self.auth 两个值,一个值最终给了Request对象的user,认证失败,则抛异常:APIException 或者是AuthenticationFailed.
- 认证类执行认证的视图类中配置 authentication_classes = [自定义的认证类, ]
- 认证类必须单独存放在py文件内,若防止在view内,使用全局配置时候,无法使用
- 必须继承 BaseAuthentication
- from rest_framework.authentication import BaseAuthentication
- 认证类内必须重写 authenticate(self, request) 方法,request参数必须传入
- 若后续有其他认证类需要执行,必须返回空!!
- 若后续不无其他认证类需要执行,则返回两个值 - 对应DRF内Request对象User类内_authenticate方法执行
- 若认证失败,抛出 exceptions.APIException 异常
- from rest_framework import exceptions
- 或 from rest_framework.exceptions import AuthenticationFailed
例子看参阅 https://www.cnblogs.com/clark1990/p/17152813.html