• 三大认证


    一、drf 总结

    """
    1)APIView的请求生命周期
        as_view():路由配置,禁用csrf
        dispatch():请求分发,请求解析、三大认证、异常处理、响应渲染
        request._request、request.query_params、request.data、request.META(请求头等诸多配置)
        
    2)序列化组件
        i)视图类中使用序列化
        serializer = UserModelSerializer(
            instance="对象(们)",
            data="数据(们)",
            many=False|True,  # 与数据或对象配套,代表操作的是否是多个
            partial=False|True,  # 运用在局部修改中,所以校验可以选填(required=False)
            context={'request': request}  # 视图、序列化传参 
        )
        serializer.is_valid(raise_exception=False|True)  # 校验
        serializer.save()  # 入库
        serializer.data  # 序列化后的数据
        serializer.errors  # 校验失败的信息
        
        ii)Meta配置类中的配置
        model:关联的Model类
        fields:所以序列化与反序列化字段
        extra_kwargs:简单的校验规则
        exclude:除某些字段
        depth:连表深度
        
        iii)自定义校验规则
        validate_字段名:局部校验钩子
        validate:全局校验钩子
        
        iv)入库方法
        create:增数据入库
        update:改数据入库
        后期这两个方法可能会被重写:涉及一些字段加密解密处理、不仅仅是单表入库操作
                user = User.create()
                UserDetail.create(user_id=user.id)
        
        v)自定义字段
        @property:在model类中自定义序列化字段
        自定义字段 = serializers.字段类型(write_only=True, 其他规则):在serializer类中的自定义反序列化字段
        系统字段 = serializers.字段类型(规则):覆盖字段,可以设置为只读、只写、可读可写
                外键字段的字段类型:PrimaryKeyRalatedField
        
        vi)如果有群改操作
            自定义ListSerializer子类,重写update方法
            在相关ModelSerializer中用list_serializer_class配置进行关联
            
        重(难)点:
        i)在视图类中初始化序列化类对象是的参数选择
        ii)指定好所以的序列化与反序列化字段
        iii)全局校验钩子的逻辑(难点)
        iv)是否要重写入库方法(难点)
    
    
    3)视图家族
        两个基类:APIView、GenericAPIVAPIView
            APIView:禁用csrf、解析、认证、渲染...
            GenericAPIVAPIView:禁用csrf、解析、认证、渲染... + 三个属性三个方法
            
        工具类:mixin包下的五个类,使用GenericAPIVAPIView的三个属性三个方法(过渡)
        
        工具视图类:mixin包下的类 + GenericAPIVAPIView 的组合形成的类
            配置三个属性 + 是否需要重写get、post等方法
        
        视图集:ViewSetMixin重写as_view方法,可以自定义 请求方式 - 响应函数 的映射关系
            配置三个属性 + mixin包下的类 + GenericViewSet
            ViewSet
    
    4)路由组件:SimpleRouter
    
    5)权限认证
        i)RBAC:Role-Based Access Control - 基于角色权限的认证规则
            权限六表:用户表、分组表、权限表 + 三个关系表
            
        ii)auth六表是否需要重写或断关联
            不需要
            
        iii)admin|xadmin|自定义 提供的后台管理项目
            
        iv)前台接口权限:三大认证
    """

    二、项目初始化

    settings.py

    INSTALLED_APPS = [
        # ...
        'rest_framework',
    ]
    
    MEDIA_URL = '/media/'
    MEDIA_ROOT = os.path.join(BASE_DIR, 'media')
    
    # 自定义用户表
    AUTH_USER_MODEL = 'api.User'

    主urls.py

    from django.conf.urls import url, include
    from django.contrib import admin
    
    from django.views.static import serve
    from django.conf import settings
    urlpatterns = [
        url(r'^admin/', admin.site.urls),
        # 路由分发
        url(r'^api/', include('api.urls')),
    
        url(r'^media/(?P<path>).*', serve, {'document_root': settings.MEDIA_ROOT}),
    ]

    子urls.py

    from django.conf.urls import url, include
    from rest_framework.routers import SimpleRouter
    router = SimpleRouter()
    from . import views
    
    # 路由注册
    # router.register('register', views.RegisterViewSet, 'register')
    
    urlpatterns = [
    
        url('', include(router.urls))
    ]

    models.py

    from django.contrib.auth.models import AbstractUser
    from django.db import models
    
    
    class User(AbstractUser):
        mobile = models.CharField(max_length=11, unique=True, verbose_name='移动电话')
        icon = models.ImageField(upload_to='icon', default='icon/default.png', verbose_name='头像')
    
        class Meta:
            db_table = 'o_user'
            verbose_name_plural = '用户表'
    
        def __str__(self):
            return self.username
    
    
    class Book(models.Model):
        name = models.CharField(max_length=64, verbose_name='书名')
    
        class Meta:
            db_table = 'o_book'
            verbose_name_plural = '书表'
    
        def __str__(self):
            return self.name
    
    
    class Car(models.Model):
        name = models.CharField(max_length=64, verbose_name='车名')
    
        class Meta:
            db_table = 'o_car'
            verbose_name_plural = '车表'
    
        def __str__(self):
            return self.name

    三、资源接口

    注册接口

    urls.py

    router.register('register', views.RegisterViewSet, 'register')

    views.py

    from rest_framework.viewsets import GenericViewSet, ModelViewSet
    from rest_framework import mixins
    from . import models, serializers
    
    class RegisterViewSet(GenericViewSet, mixins.CreateModelMixin):
        queryset = models.User.objects.filter(is_active=True).all()
        serializer_class = serializers.RegisterSerializer

    serializers.py

    from rest_framework import serializers
    from rest_framework.exceptions import ValidationError
    from . import models
    
    
    class RegisterSerializer(serializers.ModelSerializer):
        re_password = serializers.CharField(write_only=True, min_length=8, max_length=18)
        class Meta:
            model = models.User
            fields = ('username', 'password', 're_password', 'mobile')
            extra_kwargs = {
                'password': {
                    'write_only': True,
                    'min_length': 8,
                    'max_length': 18
                }
            }
    
        # username和mobile可以自定义局部钩子校验(省略)
    
        def validate(self, attrs):
            password = attrs.get('password')
            re_password = attrs.pop('re_password')
            if password != re_password:
                raise ValidationError({'re_password': 'password confirm error'})
            return attrs
    
        # 需要重写create,创建用户需要密文
        def create(self, validated_data):
            return models.User.objects.create_user(**validated_data)

    用户中心接口

    urls.py

    router.register('user/center', views.UserCenterViewSet, 'center')

    views.py

    class UserCenterViewSet(GenericViewSet, mixins.RetrieveModelMixin):
        queryset = models.User.objects.filter(is_active=True).all()
        serializer_class = serializers.UserCenterSerializer

    serializers.py

    class UserCenterSerializer(serializers.ModelSerializer):
        class Meta:
            model = models.User
            fields = ('username', 'mobile', 'icon', 'email')

    图书资源接口

    urls.py

    router.register('books', views.BookViewSet, 'book')

    views.py

    class BookViewSet(ModelViewSet):
        queryset = models.Book.objects.all()
        serializer_class = serializers.BookSerializer

    serializers.py

    class BookSerializer(serializers.ModelSerializer):
        class Meta:
            model = models.Book
            fields = ('name', )

    四、认证组件

    1、重点

    """
    1)认证规则
    2)如何自定义认证类
    3)我们一般不需要自定义认证类,在settings中全局配置第三方 jwt 认证组件提供的认证类即可
    """

    2、自定义认证类

    """
    1)自定义认证类,继承 BaseAuthentication 类
    2)必须重写 authenticate(self, request) 方法
        没有认证信息,返回None:匿名用户(游客) => 匿名用户request.user也有值,就是"匿名对象(Anonymous)"
        有认证信息,且通过,返回(user, token):合法用户 => user对象会存到request.user中
        有认证信息,不通过,抛异常:非法用户
    """

    五、权限组件

    1、重点

    """
    1)权限规则
    2)如何自定义权限类
    3)我们一般在视图类中局部配置drf提供的权限类,但是也会自定义权限类完成局部配置
    """

    2、自定义权限类

    """
    1)自定义权限类,继承 BasePermission 类
    2)必须重写 has_permission(self, request, view): 方法
        设置权限条件,条件通过,返回True:有权限
        设置权限条件,条件失败,返回False:有权限
        
    3)drf提供的权限类:
    AllowAny:匿名与合法用户都可以
    IsAuthenticated:必须登录,只有合法用户可以
    IsAdminUser:必须是admin后台用户
    IsAuthenticatedOrReadOnly:匿名只读,合法用户无限制
    """

    六、jwt(json web token)

    1、jwt的优点

    """ jwt优势
    1)没有数据库写操作,高效
    2)服务器不存token,低耗
    3)签发校验都是算法,集群
    """

    2、示意图

     3、jwt认证算法:签发与校验

    """
    1)jwt分三段式:头.体.签名 (head.payload.sgin)
    2)头和体是可逆加密,让服务器可以反解出user对象;签名是不可逆加密,保证整个token的安全性的
    3)头体签名三部分,都是采用json格式的字符串,进行加密,可逆加密一般采用base64算法,不可逆加密一般采用hash(md5)算法
    4)头中的内容是基本信息:公司信息、项目组信息、token采用的加密方式信息
    {
        "company": "公司信息",
        ...
    }
    5)体中的内容是关键信息:用户主键、用户名、签发时客户端信息(设备号、地址)、过期时间
    {
        "user_id": 1,
        ...
    }
    6)签名中的内容时安全信息:头的加密结果 + 体的加密结果 + 服务器不对外公开的安全码 进行md5加密
    {
        "head": "头的加密字符串",
        "payload": "体的加密字符串",
        "secret_key": "安全码"
    }
    """

    签发:根据登录请求提交来的 账号 + 密码 + 设备信息 签发token

    """
    1)用基本信息存储json字典,采用base64算法加密得到 头字符串
    2)用关键信息存储json字典,采用base64算法加密得到 体字符串
    3)用头、体加密字符串再加安全码信息存储json字典,采用hash md5算法加密得到 签名字符串
    
    账号密码就能根据User表得到user对象,形成的三段字符串用 . 拼接成token返回给前台
    """

    校验:根据客户端带token的请求,反解出url对象

    """
    1)将token按 . 拆分为三段字符串,第一段 头加密字符串 一般不需要做任何处理
    2)第二段 体加密字符串,要反解出用户主键,通过主键从User表中就能得到登录用户,过期时间和设备信息都是安全信息,确保token没过期,且时同一设备来的
    3)再用 第一段 + 第二段 + 服务器安全码 不可逆md5加密,与第三段 签名字符串 进行碰撞校验,通过后才能代表第二段校验得到的user对象就是合法的登录用户
    """

    七、drf项目的jwt认证开发流程(重点)

    """
    1)用账号密码访问登录接口,登录接口逻辑中调用 签发token 算法,得到token,返回给客户端,客户端自己存到cookies中
    
    2)校验token的算法应该写在认证类中(在认证类中调用),全局配置给认证组件,所有视图类请求,都会进行认证校验,所以请求带了token,就会反解出user对象,在视图类中用request.user就能访问登录的用户
    
    注:登录接口需要做 认证 + 权限 两个局部禁用
    """

    drf-jwt框架的基本使用

    安装(终端)
    >: pip install djangorestframework-jwt
    签发token(登录接口)配置路由
    # api/urls.py
    urlpatterns = [
        # ...
        url('^login/$', ObtainJSONWebToken.as_view()),
    ]
    
    # Postman请求:/api/login/,提供username和password即可
    校验token(认证组件)全局配置下认证组件settings.py
    # drf-jwt的配置
    import datetime
    JWT_AUTH = {
        # 配置过期时间
        'JWT_EXPIRATION_DELTA': datetime.timedelta(days=7),
    }
    
    
    # drf配置(把配置放在最下方)
    REST_FRAMEWORK = {
        # 自定义三大认证配置类们
        'DEFAULT_AUTHENTICATION_CLASSES': ['rest_framework_jwt.authentication.JSONWebTokenAuthentication'],
        # 'DEFAULT_PERMISSION_CLASSES': [],
        # 'DEFAULT_THROTTLE_CLASSES': [],
    }
    需要登录才能访问的的接口测试(views.py)
    from rest_framework.permissions import IsAuthenticated
    class UserCenterViewSet(GenericViewSet, mixins.RetrieveModelMixin):
        # 设置必须登录才能访问的权限类
        permission_classes = [IsAuthenticated, ]
    
        queryset = models.User.objects.filter(is_active=True).all()
        serializer_class = serializers.UserCenterSerializer
    测试访问登录认证接口(postman)
    """
    1)用 {"username": "你的用户", "password": "你的密码"} 访问 /api/login/ 接口等到 token 字符串
    
    2)在请求头用 Authorization 携带 "jwt (在这里加一个空格) 登录得到的token" 访问 /api/user/center/1/ 接口访问个人中心
  • 相关阅读:
    【leetcode】面试题 01.04. 回文排列
    【leetcode】将数组分成和相等的三个部分
    【leetcode】杨辉三角
    【leetcode】杨辉三角 II
    【leetcode】判断路径是否相交
    【leetcode】路径总和
    【leetcode】山脉数组的峰顶索引
    053-4
    053-151
    053-272
  • 原文地址:https://www.cnblogs.com/yafeng666/p/12359587.html
Copyright © 2020-2023  润新知