RESF framework框架-认证源码流程解析

282 阅读4分钟

django rest framework框架

这是我参与8月更文挑战的第23天,活动详情查看:8月更文挑战

感激相遇 你好 我是y大壮

作者:y大壮
链接:juejin.cn/user/756923… 来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

🌊🌈关于前言:

文章部分内容及图片出自网络,如有问题请与我本人联系

🌊🌈关于内容:


作者:y大壮
链接:juejin.cn/post/699902… 来源:掘金
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

  1. pip install djangorestframework

  2. 在settings中配置

    INSTALLED_APPS = [
        'rest_framework',  # DRF
    ]
    

1、认证

认证组件一般用在用户的登录注册上,用于判断当前的用户是否合法,并跳转到登陆成功或失败页面。
有些API需要用户登录成功之后,才能访问;有些无需登录就能访问。
    解决方式:
	把token值存放起来

1.1 自定义认证方式(基本使用):

APIView为我们提供了很多的方法, 当用户登录或者注册的时候,我们会给用户token。所以我们在进行认证的时候,只用去检测token在不在就可以了

!! 我们是继承了认证的方法,所有authenticate_header一定要加上

from django.views import View
from rest_framework.views import APIView
from rest_framework.authentication import BasicAuthentication
from rest_framework import exceptions
from rest_framework.request import Request

class MyAuthentication(object):
    def authenticate(self,request):
        token = request._request.GET.get('token')  # 获取token值
        # 获取用户名和密码,去数据校验
        if not token:
       		raise exceptions.AuthenticationFailed('用户认证失败')
        return ("alex",None)  # 有token值的时候干嘛干嘛

    def authenticate_header(self,val):
    	pass

class DogView(APIView):
    authentication_classes = [MyAuthentication,]

    def get(self,request,*args,**kwargs):
        print(request)
        print(request.user)
        ret  = {  # 设置响应消息
        'code':1000,
        'msg':'xxx'
        }
        return HttpResponse(json.dumps(ret),status=201)

    def post(self,request,*args,**kwargs):
    	return HttpResponse('创建')

    def put(self,request,*args,**kwargs):
    	return HttpResponse('更新')

    def delete(self,request,*args,**kwargs):
    	return HttpResponse('删除')

1.2 认证流程原理:

dispatch开始

# 1.APIView下的dispatch
    def dispatch(self, request, *args, **kwargs):
        self.args = args
        self.kwargs = kwargs
        # 获取的参数
        # 把获取的参数,经过initialize_request构建成新的request
        request = self.initialize_request(request, *args, **kwargs)
        # 获取原生request,request._request
        # 获取认证类的对象,request.authenticators
        self.request = request
        self.headers = self.default_response_headers  # deprecate?

# 2.initial(self, request, *args, **kwargs):

# 3.perform_authentication(self, request)
# 4.原生的request
@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'):
        with wrap_attributeerrors():
            # 获取认证对象,进行一步的认证
            self._authenticate()  # 进入认证
    return self._user
#  5.self._authenticate()、进入def _not_authenticated(self):方法,为None,或者有值
def _authenticate(self):
    """
    Attempt to authenticate the request using each authentication instance
    in turn.
    """
    # [BasicAuthentication对象,]
    for authenticator in self.authenticators:  # 遍历认证对象,执行认证方法
        try:
            # 执行认证类的authenticate方法
            # 1. 如果authenticate方法抛出异常,self_not_authenticate()执行
            # 2. 有返回值必须是元组:(request.user,request.auth)
            # 3. 返回None的话,下个认证来进行处理
            user_auth_tuple = authenticator.authenticate(self) # 执行这个对象的认证方法(认证是否以及登录),如果没有就报错
        except exceptions.APIException:
            self._not_authenticated()  # 没有进入_not_authenticated,返回对应的错误消息
            raise

        if user_auth_tuple is not None:  # 给响应的参数赋值
            self._authenticator = authenticator
            self.user, self.auth = user_auth_tuple
            return

    self._not_authenticated()

2、自定义认证类示例

class Authtication(object):
    def authenticate(self, request):
        token = request._request.GET.get('token')
        token_obj = models.UserToken.objects.filter(token=token).first()
        if not token_obj:
            raise exceptions.AuthenticationFailed('用户未认证')
        return (token_obj.user, token_obj)  # 在rest fromwork内部会将这二个字段赋值给request,以供后续的使用(对应request.user,request.auth)

    def authenticate_header(self, request):
        pass


class OrderView(APIView):
    authentication_classes = [Authtication, ]  # 方式二:

    def get(self, request, *args, **kwargs):
        # 方式一:
        # token = request._request.GET.get('token')
        # if not token:
        #     raise exceptions.AuthenticationFailed('用户未认证')
        ret = {'code': 1000, 'message': 'ok!', 'data': None}
        try:
            ret['data'] = ORDER_DICT
        except Exception as e:
            ret['code'] = 1001
            ret['message'] = '找不到服务器'
        return JsonResponse(ret)

3、自定义全局认证&局部认证

全局认证
  1. 把自定义的认证类封装到文件夹中

    # app02.utils.auth.py
    
    from rest_framework import exceptions
    
    from .. import models
    
    
    class Authtication(object):
        def authenticate(self, request):
            token = request._request.GET.get('token')
            token_obj = models.UserToken.objects.filter(token=token).first()
            if not token_obj:
                raise exceptions.AuthenticationFailed('用户未认证')
            return (token_obj.user, token_obj)  # 在rest fromwork内部会将这二个字段赋值给request,以供后续的使用(对应request.user,request.auth)
    
        def authenticate_header(self, request):
            pass
    
    
    class FirstAuthtication(object):
        def authenticate(self, request):
            pass  # pass返回的是None (搞成匿名用户的示例)
    
        def authenticate_header(self, request):
            pass
    
  2. 在settings中配置

    REST_FRAMEWORK = {
        'DEFAULT_AUTHENTICATION_CLASSES': ['app02.utils.auth.FirstAuthtication', 'app02.utils.auth.Authtication']
    }
    
  3. 使用

    # 因为这样定义是全局的,所以所有的视图都可以使用。
    
    # 我们可以设置authentication_classes=[] 这样就可以不用使用全局的认证
    class AuthLoginView(APIView):
        """用户登录"""
        authentication_classes = []
    
局部认证
# 自定义好后直接使用就可以authentication_classes = [Authtication, ]

class Authtication(object):
    def authenticate(self, request):
        token = request._request.GET.get('token')
        token_obj = models.UserToken.objects.filter(token=token).first()
        if not token_obj:
            raise exceptions.AuthenticationFailed('用户未认证')
        return (token_obj.user, token_obj)  # 在rest fromwork内部会将这二个字段赋值给request,以供后续的使用(对应request.user,request.auth)

    def authenticate_header(self, request):
        pass


class OrderView(APIView):
    authentication_classes = [Authtication, ]  # 方式二:

    def get(self, request, *args, **kwargs):
        # 方式一:
        # token = request._request.GET.get('token')
        # if not token:
        #     raise exceptions.AuthenticationFailed('用户未认证')
        ret = {'code': 1000, 'message': 'ok!', 'data': None}
        try:
            ret['data'] = ORDER_DICT
        except Exception as e:
            ret['code'] = 1001
            ret['message'] = '找不到服务器'
        return JsonResponse(ret)

4、匿名用户

  1. settings.py

    匿名用户就是设置request.user和request.auth为None没有信息

    REST_FRAMEWORK = {
        # 'DEFAULT_AUTHENTICATION_CLASSES': ['app02.utils.auth.FirstAuthtication', 'app02.utils.auth.Authtication'],
        'DEFAULT_AUTHENTICATION_CLASSES': ['app02.utils.auth.FirstAuthtication'],  # 匿名用户(因为我们在封装的时候什么都没有写,让它返回None)
        # 'UNAUTHENTICATED_USER': lambda: '匿名用户',
        'UNAUTHENTICATED_USER': None,
        'UNAUTHENTICATED_TOKEN': None,
    }
    
  2. app02.utils.auth.py

    class FirstAuthtication(object):
        def authenticate(self, request):
            print('匿名用户')
            pass  # pass返回的是None (搞成匿名用户的示例)
    
        def authenticate_header(self, request):
            pass
    

5、认证Authentication(resf自带认证)

  1. 在settings.py配置

    REST_FRAMEWORK = {
        'DEFAULT_AUTHENTICATION_CLASSES': (
            'rest_framework.authentication.SessionAuthentication',  # session认证
            'rest_framework.authentication.BasicAuthentication',   # 基本认证
        )
    }
    
  2. 每个视图通过authentication_classess来添加认证

    from rest_framework.authentication import SessionAuthentication, BasicAuthentication
    from rest_framework.views import APIView
    
    class ExampleView(APIView):
        authentication_classes = (SessionAuthentication, BasicAuthentication)
       
    
  3. 认证失败会有两种可能的返回值

  • 401 Unauthorized 未认证

  • 403 Permission Denied 权限被禁止