zoukankan      html  css  js  c++  java
  • DRF 认证、权限、频率认证、异常组件

    DRF 权限认证

    导入:

    用户量极大的常规项目,会分两种用户:前台用户(三大认证) 和 后台用户(BRAC来管理)

    结论:没有特殊要求的Django项目可以直接采用Auth组件的权限六表,不需要自定义六个表,也不需要断开表关系,但可能需要自定义User表

    三大认证流程

    认证

    工作原理

    • 返回None => 游客
    • 返回元组(user,auth) => 登录用户
    • 抛出异常 => 非法用户

    前台对于用户信息进行的判断

    1)如果前台没有携带认证信息,直接判定该请求为游客 => 代表认证通过

    2)如果前台携带认证信息,定位为登录用户,将登录的用户user对象保存在 requset.user 中 => 代表认证通过

    3)如果前台携带了认证信息但没有认证通过,一般都定义为非法用户 

    5)认证组件通常在settings中全局配置

    权限

    工作原理

    • 返回False => 没有权限,将信息返回给前台
    • 返回True => 拥有权限,进行下一步认证(频率认证)

    认证组件

    自定义认证类

    authentica源码分析:

    1、自定义认证类,继承 BaseAuthentication 类

    2、必须重写 authenticate(self, request) 方法

    • 没有认证信息,返回None:匿名用户(游客) => 匿名用户request.user也有值,就是"匿名对象(Anonymous)"
    • 有认证信息 且通过,返回(user, token):合法用户 => user对象会存到request.user中
    • 有认证信息,不通过,抛异常:非法用户

    认证组件项目使用:多方式登录

    urls.py
    # 自定义登录(重点):post请求 => 查操作(签发token返回给前台) - 自定义路由映射
    url('^user/login/$', views.LoginViewSet.as_view({'post': 'login'})),
    views.py
    # 重点:自定义login,完成多方式登录
    from rest_framework.viewsets import ViewSet
    from rest_framework.response import Response
    class LoginViewSet(ViewSet):
        # 登录接口,要取消所有的认证与权限规则,也就是要做局部禁用操作(空配置)
        authentication_classes = []
        permission_classes = []
    
        # 需要和mixins结合使用,继承GenericViewSet,不需要则继承ViewSet
        # 为什么继承视图集,不去继承工具视图或视图基类,因为视图集可以自定义路由映射:
        #       可以做到get映射get,get映射list,还可以做到自定义(灵活)
        def login(self, request, *args, **kwargs):
            serializer = serializers.LoginSerializer(data=request.data, context={'request': request})
            serializer.is_valid(raise_exception=True)
            token = serializer.context.get('token')
            return Response({"token": token})
    serializers.py
    from rest_framework_jwt.serializers import jwt_payload_handler, jwt_encode_handler
    
    # 重点:自定义login,完成多方式登录
    class LoginSerializer(serializers.ModelSerializer):
        # 登录请求,走的是post方法,默认post方法完成的是create入库校验,所以唯一约束的字段,会进行数据库唯一校验,导致逻辑相悖
        # 需要覆盖系统字段,自定义校验规则,就可以避免完成多余的不必要校验,如唯一字段校验
        username = serializers.CharField()
        class Meta:
            model = models.User
            # 结合前台登录布局:采用账号密码登录,或手机密码登录,布局一致,所以不管账号还是手机号,都用username字段提交的
            fields = ('username', 'password')
    
        def validate(self, attrs):
            # 在全局钩子中,才能提供提供的所需数据,整体校验得到user
            # 再就可以调用签发token算法(drf-jwt框架提供的),将user信息转换为token
            # 将token存放到context属性中,传给外键视图类使用
            user = self._get_user(attrs)
            payload = jwt_payload_handler(user)
            token = jwt_encode_handler(payload)
            self.context['token'] = token
            return attrs
    
        # 多方式登录
        def _get_user(self, attrs):
            username = attrs.get('username')
            password = attrs.get('password')
            import re
            if re.match(r'^1[3-9][0-9]{9}$', username):
                # 手机登录
                user = models.User.objects.filter(mobile=username, is_active=True).first()
            elif re.match(r'^.+@.+$', username):
                # 邮箱登录
                user = models.User.objects.filter(email=username, is_active=True).first()
            else:
                # 账号登录
                user = models.User.objects.filter(username=username, is_active=True).first()
            if user and user.check_password(password):
                return user
    
            raise ValidationError({'user': 'user error'})

    权限组件

    drf提供的权限类

    AllowAny:匿名与合法用户都可以

    IsAuthenticated:必须登录,只有合法用户可以

    IsAdminUser:必须是admin后台用户

    IsAuthenticatedOrReadOnly:匿名只读,合法用户无限制

    自定义权限类

    1、自定义权限类,继承 BasePermission 类

    2、必须重写 def has_permission(self, request, view): 方法

    设置权限条件,条件通过,返回True:有权限

    设置权限条件,条件失败,返回False:无权限

    权限组件项目使用:vip用户权限

    数据准备

    """
    1)User表创建两条数据
    2)Group表创建一条数据,name叫vip
    3)操作User和Group的关系表,让1号用户属于1号vip组
    """
    permissions.py
    from rest_framework.permissions import BasePermission
    
    from django.contrib.auth.models import Group
    class IsVipUser(BasePermission):
        def has_permission(self, request, view):
            if request.user and request.user.is_authenticated:  # 必须是合法用户
                try:
                    vip_group = Group.objects.get(name='vip')
                    if vip_group in request.user.groups.all():  # 用户可能不属于任何分组
                        return True  # 必须是vip分组用户
                except:
                    pass
    
            return False
    views.py
    from .permissions import IsVipUser
    class CarViewSet(ModelViewSet):
        permission_classes = [IsVipUser]
    
        queryset = models.Car.objects.all()
        serializer_class = serializers.CarSerializer
    serializers.py
    class CarSerializer(serializers.ModelSerializer):
        class Meta:
            model = models.Car
            fields = ('name', )
    urls.py
    router.register('cars', views.CarViewSet, 'car')

    频率组件

    重点

    1、如何自定义频率类

    2、频率校验的规则

    3、自定义频率类是最常见的:短信接口一分钟只能发生一条短信

    自定义频率类

    """
    1)自定义类继承SimpleRateThrottle
    2)设置类属性scope,值就是一个字符串,与settings中的DEFAULT_THROTTLE_RATES进行对应,
       DEFAULT_THROTTLE_RATES就是设置scope绑定的类的频率规则:1/min 就代表一分钟只能访问一次
    3)重写 get_cache_key(self, request, view) 方法,指定限制条件
        不满足限制条件,返回None:代表对这类请求不进行频率限制
        满足限制条件,返回一个字符串(是动态的):代表对这类请求进行频率限制
            短信频率限制类,返回 "throttling_%(mobile)s" % {"mobile": 实际请求来的电话}
    """

    系统提供的频率类

    • UserRateThrottle: 限制所有用户访问频率
    • AnonRateThrottle:只限制匿名用户访问频率

    异常组件项目使用:记录异常信息到日志文件

    处理异常模块的目的是:不管任何错误,都有必要进行日志记录(线上项目只能通过记录的日志查看出现过的错误)

    settings.py
    REST_FRAMEWORK = {
        # ...
        # 异常模块
        # 'EXCEPTION_HANDLER': 'rest_framework.views.exception_handler',  # 源码,只处理客户端异常
        'EXCEPTION_HANDLER': 'api.exception.exception_handler',  #自定义异常处理,(客户端、服务器都处理)
    }
    exception.py
    from rest_framework.views import exception_handler as drf_exception_handler
    from rest_framework.response import Response
    def exception_handler(exc, context):
        # 只处理客户端异常,不处理服务器异常,
        # 如果是客户端异常,response就是可以直接返回给前台的Response对象
        response = drf_exception_handler(exc, context)
    
        if response is None:
            # 没有处理的服务器异常,处理一下
            # 其实给前台返回 服务器异常 几个字就行了
            response = Response({'detail': '%s' % exc})
    
        # 需要结合日志模块进行日志记录的
        return response

    RBAC权限六表(RBAC - Role-Based Access Control)

    案例:

    models.py
    from django.db import models
    
    # RBAC - Role-Based Access Control
    # Django的 Auth组件 采用的认证规则就是RBAC
    
    from django.contrib.auth.models import AbstractUser
    class User(AbstractUser):
        mobile = models.CharField(max_length=11, unique=True)
    
        def __str__(self):
            return self.username
    
    
    class Book(models.Model):
        name = models.CharField(max_length=64)
    
        def __str__(self):
            return self.name
    
    
    class Car(models.Model):
        name = models.CharField(max_length=64)
    
        def __str__(self):
            return self.name
    settings.py
    # 自定义User表,要配置
    AUTH_USER_MODEL = 'api.User'
    admin.py
    from django.contrib import admin
    from . import models
    
    from django.contrib.auth.admin import UserAdmin as DjangoUserAdmin
    
    # 自定义User表后,admin界面管理User类
    class UserAdmin(DjangoUserAdmin):
        # 添加用户课操作字段
        add_fieldsets = (
            (None, {
                'classes': ('wide',),
                'fields': ('username', 'password1', 'password2', 'is_staff', 'mobile', 'groups', 'user_permissions'),
            }),
        )
        # 展示用户呈现的字段
        list_display = ('username', 'mobile', 'is_staff', 'is_active', 'is_superuser')
    
    
    admin.site.register(models.User, UserAdmin)
    admin.site.register(models.Book)
    admin.site.register(models.Car)

    局部、全局、默认配置

    做项目是否要分表管理前后台用户

    1)是否需要分表
    
    答案:不需要
    
    理由:前后台用户共存的项目,后台用户量都是很少;做人员管理的项目,基本上都是后台用户;前后台用户量都大的会分两个项目处理
    
    2)用户权限六表是否需要断关联
    
    答案:不需要
    
    理由:前台用户占主导的项目,几乎需求只会和User一个表有关;后台用户占主导的项目,用户量不会太大
    
    3)Django项目有没有必须自定义RBAC六表
    
    答案:不需要
    
    理由:auth组件功能十分强大且健全(验证密码,创建用户等各种功能);admin、xadmin、jwt、drf-jwt组件都是依赖auth组件的(自定义RBAC六表,插件都需要自定义,成本极高)

    总结

    1、后台用户对各表操作,是后台项目完成的,我们可以直接借助admin后台项目(Django自带的)

    2、后期也可以用xadmin框架来做后台用户权限管理

    3、前台用户的权限管理如何处理

    定义了一堆数据接口的视图类,不同的登录用户是否能访问这些视图类,能就代表有权限,不能就代表无权限

    前台用户权限用drf框架的 三大认证

    注:前台用户权限会基于 jwt 认证

  • 相关阅读:
    上传相同文件名的时候不能触发change事件的解决方案
    react自定义组件属性类型检测
    在react项目当中使用redux
    redux使用需要注意的地方
    关于在redux当中 reducer是如何知道传入的state是初始化state下面的哪一条数据
    react当中子组件改变父组件的状态
    vscode编辑器开发react时,设置使emmet支持自定义组件
    Sass之二(进阶篇)
    Sass之一(基础篇)
    sass ruby环境 安装配置,使用sublime text3 中sass
  • 原文地址:https://www.cnblogs.com/baohanblog/p/12345613.html
Copyright © 2011-2022 走看看