zoukankan      html  css  js  c++  java
  • DRF之认证组件

    一:认证组件介绍

    (1)认证组件入口

    (1)视图

    APIView的dispath(self, request, *args, **kwargs)   

    (2)任务分发

    dispath方法内 self.initial(request, *args, **kwargs) 进入三大认证

    (3)认证组件

       self.perform_authentication(request)

    (4)认证功能介绍

      (1)其主要用来对用户进行认证

      (2)检验用户 ----> 普通游客 | 合法用户 | 非法用户

      (3)游客:代表认证通过 直接进入下一步(权限校验)

      (2)合法用户:携带验证信息进行验证 验证通过将用户存储进入request.user中 再次进行下一步校验

      (3)非法用户:携带验证信息进行验证 验证失败直接抛出异常 返回403权限问题

    (2)源码分析

    (1)第一步APIView/dispatch/initial

     def initial(self, request, *args, **kwargs):# Ensure that the incoming request is permitted
            self.perform_authentication(request) # 认证功能
            self.check_permissions(request)      # 访问权限功能
            self.check_throttles(request)       # 频率功能

    (2)第二步进入认证功能

       def perform_authentication(self, request):
    
            request.user   # 得到一个方法属性 get方法
         PS: 如果是复制属性 应该是request.user = XXX

    (3)第三步进入request/user

        @property
        def user(self):
            if not hasattr(self, '_user'):
                with wrap_attributeerrors():
                    self._authenticate()     # 没有用户认证处用户
            return self._user  # 如果有直接返回用户

    (4)第四步_authenticate

        def _authenticate(self):
            # self.authenticators:一堆认证类产生序列化认证对象的集合体(列表)
            for authenticator in self.authenticators:   # 循环遍历集合体拿到一个个认证对象
                try:
                    '''
                    authenticator.authenticate:认证对象调用认证功能
                    user_auth_tuple:拿到登录的用户与用户信息的返回值
                    
                    调用改方法传入两个参数 self,request
                    self:当前认证类对象
                    request:当前请求用户
                    
                    '''
                    user_auth_tuple = authenticator.authenticate(self)
                except exceptions.APIException:
                    # 抛出异常代表认证失败
                    self._not_authenticated()
                    raise
    
                if user_auth_tuple is not None:
                    self._authenticator = authenticator
                    # 如果有返回值 将登录用户 与 验证信息 保存在 request.user ,request.author
                    self.user, self.auth = user_auth_tuple
    
                    return
            # 如果返回值为空 代表认证通过 但是没有登录用户 与验证信息 表示当前用户为游客用户
            self._not_authenticated()

    (5)自定义认证组件

    (1)全局settings文件配置

    REST_FRAMEWORK = {
    # 认证类配置
        'DEFAULT_AUTHENTICATION_CLASSES': [
            'api.authentications.MyAuthentication',  # 自定义认证组件
        ],
       
    }

    (2)全局settings默认配置

     # 认证类配置
        'DEFAULT_AUTHENTICATION_CLASSES': [
             'rest_framework.authentication.SessionAuthentication',
             'rest_framework.authentication.BasicAuthentication',
           
        ],

    (3)自定义文件配置api/Authentication

    from rest_framework.exceptions import AuthenticationFailed
    from rest_framework.authentication import BaseAuthentication
    from . import models
    class MyAuthentication(BaseAuthentication):
        def authenticate(self, request):
            '''
            前台在请求头携带认证信息,
            且默认规范用 Authorization 字段携带认证信息,
            后台固定在请求对象的META字段中 HTTP_AUTHORIZATION 获取
    
            '''
            auth = request.META.get('HTTP_AUTHORIZATION',None)   # 可以不携带认证信息
    
            if auth is None:  # 如果为空则表明游客
                return None  # 没有登录用户 与 返回信息
    
            auth_list = auth.split()  # 设置认证小规则(两段式)
    
            # 判断用户是否合法
            if not (len(auth_list) == 2 and auth_list[0].lower() == 'auth'):
                raise AuthenticationFailed('认证信息有误 非法用户')  # 非法的请求 直接抛出异常
    
            # 解析合法的用户
            if not auth_list[1] == 'qwe.asd.zxc':   # 假设通过解析'qwe.asd.zxc' 可以解析处合法用户
                raise AuthenticationFailed('用户校验失败 非法用户')
    
            user_obj = models.User.objects.filter(username='admin').first()
            if not user_obj:
                raise AuthenticationFailed('用户数据有误 非法用户')
            return (user_obj,None)   # 合法将用户返回 验证信息不返回

    (4)视图层

    from rest_framework.views import APIView
    from rest_framework.response import Response
    
    class TestAPIView(APIView):
        def get(self,request,*args,**kwargs):
            '''
            测试一:前段不输入校验信息 获取用户属于匿名用户
            测试二:前段加入验证信息  获取用户属于解析用户 admin
            '''
            print(request.user)
            return Response(
                {
                    'status':0,
                    'msg':'测试成功'
                }
            )

     二:权限组件介绍

    (1)权限组件入口

    (1)视图

    APIView的dispath(self, request, *args, **kwargs)   

    (2)任务分发

    dispath方法内 self.initial(request, *args, **kwargs) 进入三大认证

    (3)权限组件

    self.check_permissions(request)   

    (2)源码分析

    (1)源码分析

     def check_permissions(self, request):
            '''
            get_permissions:产生权限对象的类
            参数:
                self:产生权限的类的对象
                request:用户请求
                self:views实例化产生对象
            '''
            for permission in self.get_permissions():  # 循环遍历
                '''
                has_permission:返回值布尔值
                
                '''
                if not permission.has_permission(request, self):  # 判断布尔值 如果为真则获取所有权限 反之则为假
                    self.permission_denied(
                        request, message=getattr(permission, 'message', None)
                    )
          # PS:默认登录用户 与游客有全部权限

    (2)系统权限类

    (1)AllowAny:游客与登录用户都含有权限

    class AllowAny(BasePermission):
    
        def has_permission(self, request, view):
            return True

    (2)IsAuthenticated:登录用户且验证通过的用户

    class IsAuthenticated(BasePermission):
        def has_permission(self, request, view):
            return bool(request.user and request.user.is_authenticated)

    (3)IsAdminUser:登录用户 且必须是后台管理员

    class IsAdminUser(BasePermission):
        def has_permission(self, request, view):
            return bool(request.user and request.user.is_staff)

    (4)IsAuthenticatedOrReadOnly:只读请求 或者合法用户

      (1)游客:只读

      (2)登录用户:含有全部权限

    class IsAuthenticatedOrReadOnly(BasePermission):
    
        def has_permission(self, request, view):
            return bool(
                request.method in SAFE_METHODS or
                request.user and
                request.user.is_authenticated
            )

    (3)代码示例

    (1)全局settings

    REST_FRAMEWORK = {
        # 权限类配置
        'DEFAULT_PERMISSION_CLASSES': [
            'rest_framework.permissions.AllowAny',
        ],
    }

    (2)视图层

    from rest_framework.permissions import IsAuthenticated
    
    
    # 只有登录用户才有权限
    class TestAuthenticatedAPIView(APIView):
        permission_classes = [IsAuthenticated]  # 使用 IsAuthenticated 不使用全局AllowAny
    
        def get(self, request, *args, **kwargs):
            return Response(
                {
                    'status': 0,
                    'msg': "登录且合法用户可以访问"
                }
            )
    
    
    # 游客只读,登录无限制
    from rest_framework.permissions import IsAuthenticatedOrReadOnly
    
    
    class TestAuthenticatedOrReadOnlyAPIView(APIView):
        permission_classes = [IsAuthenticatedOrReadOnly]
    
        def get(self, request, *args, **kwargs):
            return Response({
                'status': 0,
                'msg': '游客只读 登录用户无限制'
            })
    
        def post(self, request, *args, **kwargs):
            return Response({
                'status': 0,
                'msg': '游客只读 登录用户无限制'
            })

    (4)自定义权限

    (1)api/permissions


    from
    django.contrib.auth.models import Group from rest_framework.permissions import BasePermission from rest_framework.exceptions import AuthenticationFailed class MyPermission(BasePermission): def has_permission(self, request, view): print(self) # <api.permissions.MyPermission object at 0x0000000005673C50> 当前权限对象 print(request) # <api.permissions.MyPermission object at 0x0000000005673C50> 请求对象 print(view) # <api.views.TestAdminOrReadOnlyAPIView object at 0x0000000005673518> view对象 # 只读接口 read_only = request.method in ('GET', 'HEAD', 'OPTIONS') # group为有权限的分组 group = Group.objects.filter(name='管理员').first() # groups为当前用户所属的所有分组 groups = request.user.groups.all() data1 = group and groups # group groups 必须有值 data2 = group in groups # 有权限分组 必须在所有分组中 # 读接口大家都有权限,写接口必须为指定分组下的登陆用户 return read_only or (data1 and data2)

    (2)视图层

    from .permissions import MyPermission
    
    
    class TestAdminOrReadOnlyAPIView(APIView):
        permission_classes = [MyPermission]
    
        def get(self, request, *args, **kwargs):
            return Response(
                {
                    'status':0,
                    'msg':"游客可以读取数据 但是不能写数据"
                }
            )
    
        def post(self, request, *args, **kwargs):
            return Response(
                {
                    "status":0,
                    'msg':'管理员可以读写'
                }
            )

     三:频率组件

    (1)权限组件入口

    (1)视图

    APIView的dispath(self, request, *args, **kwargs)   

    (2)任务分发

    dispath方法内 self.initial(request, *args, **kwargs) 进入三大认证

    (3)权限组件

    self.check_throttles(request)   # 频率组件

    (2)核心源码分析

     for throttle in self.get_throttles():
            if not throttle.allow_request(request, self):
                # 只要频率限制了,allow_request 返回False了,才会调用wait
                throttle_durations.append(throttle.wait())
    
                if throttle_durations:
                    # Filter out `None` values which may happen in case of config / rate
                    # changes, see #1438
                    durations = [
                        duration for duration in throttle_durations
                        if duration is not None
                    ]
    
                    duration = max(durations, default=None)
                    self.throttled(request, duration)

    PS:

      (1)遍历配置的频率认证类,初始化得到一个个频率认证类对象(会调用频率认证类的 __init__() 方法)
      (2)频率认证类对象调用 allow_request 方法,判断是否限次(没有限次可访问,限次不可访问)
      (3)频率认证类对象在限次后,调用 wait 方法,获取还需等待多长时间可以进行下一次访问
            注:频率认证类都是继承 SimpleRateThrottle 类

     (3)自定义频率类

    (1)全局settings文件配置

      # 频率限制条件配置
        'DEFAULT_THROTTLE_RATES': {
            'send_msg': '1/min'
        },

    (2)api/throttles.py

    from rest_framework.throttling import SimpleRateThrottle
    
    class SendMsgRateThrottle(SimpleRateThrottle):
        scope = 'send_msg'  # 自定义一个字符串
    
        def get_cache_key(self, request, view):
            phone = request.query_params.get('phone')   # 获取前段get拼接值
    
            if not phone:  # 如果 没有值 说明无任何访问限制
                return None  # 按照源码格式来 固定返回None
              
            # 按照源码格式 此处以手机号作为身份标识
            return 'throttle_%(scope)s_%(ident)s' % {'scope': self.scope, 'ident': phone}   

    (3)路由层

        url(r'^send_msg/$', views.TestThrottles.as_view()),

    (4)视图层

    from .throttles import SendMsgRateThrottle   # 导入自定义的频率类
    
    class TestThrottles(APIView):
        throttle_classes = [SendMsgRateThrottle]  # 局部配置
    
        def get(self, request, *args, **kwargs):
            return Response({
                'status': 0,
                'msg': '访问频率get方式测试成功'
            })
    
        def post(self, request, *args, **kwargs):
            return Response({
                'status': 0,
                'msg': '访问频率post方式测试成功'
            })

    PS:

      (1)对api/send_msg/?phone = xxx 有限制

    # 例如
    http://127.0.0.1:8000/api/send_msg/?phone=1234654646

      (2)对 /api/send_msg/ 或其他接口发送无限制
      (3)对数据包提交phone的/api/phone/接口无限制
      (4)对不是phone(如mobile)字段提交的电话接口无限制

  • 相关阅读:
    JSP基础语法:注释、Scriptlet、编译指令
    JDBC的LIKE书写规范
    AWT回顾篇
    1.五子棋预备知识
    对象的生命周期回顾篇
    学习activemq(2)写个简单的程序
    activemq in action(3)剖析JMS消息(转)
    activemq in action(1)
    学习activemq(3)
    hadhoop安装
  • 原文地址:https://www.cnblogs.com/SR-Program/p/11715901.html
Copyright © 2011-2022 走看看