DRF认证

2019-09-28  本文已影响0人  上帝大人

单独看用法

你定义了一个类CBV,类继承自APIView,在里面赋值authentication_classes字段,字段认证类列表,这几个认证类都需要你自己定义。认证类中要实现authenticate()方法和authenticate_header()方法

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对象。

在执行初始化操作中,其他的先别看,先看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)

再看源码,了解全局配置

REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES':[‘app1.utils.auth.Authentication’,‘ app1.utils.auth.Authentication2’ ]
}
  • 除了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进行身份验证呢?

restframework中的认证类

BasicAuthentication,浏览器对你的用户名和密码进行加密,放到header中,在你的header中有加密后的用户名和密码,他会到header中取得加密的值,然后进行解密,得到用户名和密码进行验证。

梳理

梳理:

  1. 创建类,继承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,
}
  1. 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')
上一篇下一篇

猜你喜欢

热点阅读