自定义路由组件,Django的admin后台管理,DRF的三大认证,jwt认证

目录

一、自定义路由组件

1. 为什么要自定义路由组件

  • 在DRF中的视图家族中,有与视图家族对应的配套路由类SimpleRouter,但该类只包含了视图家族中的6大接口,其余群增,群整体改,群局部改,群删4大接口没有对应的路由。所以需要我们手动自定义路由组件

2. 自定义路由组件实例

from rest_framework.routers import Route, DynamicRoute, SimpleRouter as DRFSimpleRouter

class SimpleRouter(DRFSimpleRouter):
    routes = [
        # List route.  /资源s/
        Route(
            url=r'^{prefix}{trailing_slash}$',
            mapping={
                'get': 'list',  # 群查
                'post': 'create',  # 单增、群增
                'put': 'multiple_update',  # 群整改
                'patch': 'multiple_partial_update',  # 群局改
                'delete': 'multiple_destroy',  # 群删
            },
            name='{basename}-list',
            detail=False,
            initkwargs={'suffix': 'List'}
        ),
        # Dynamically generated list routes. Generated using
        # @action(detail=False) decorator on methods of the viewset.
        DynamicRoute(
            url=r'^{prefix}/{url_path}{trailing_slash}$',
            name='{basename}-{url_name}',
            detail=False,
            initkwargs={}
        ),
        # Detail route.  /资源s/(pk)/
        Route(
            url=r'^{prefix}/{lookup}{trailing_slash}$',
            mapping={
                'get': 'retrieve',  # 单查
                'put': 'update',  # 单整改
                'patch': 'partial_update',  # 单局改
                'delete': 'destroy'  # 单删
            },
            name='{basename}-detail',
            detail=True,
            initkwargs={'suffix': 'Instance'}
        ),
        # Dynamically generated detail routes. Generated using
        # @action(detail=True) decorator on methods of the viewset.
        DynamicRoute(
            url=r'^{prefix}/{lookup}/{url_path}{trailing_slash}$',
            name='{basename}-{url_name}',
            detail=True,
            initkwargs={}
        ),
    ]

# 对外提供router对象
router = SimpleRouter()
# eg: router.register('users', UserModelViewSet, basename='user')

二、Django的admin后台管理

  • 在Django自带的后天管理系统中,通过Django的auth模块创建的用户表对应的页面,展示的信息都可以由自己配置。

  • 实例

# admin文件中:

from django.contrib import admin
from . import models
from django.contrib.auth.admin import UserAdmin as AuthUserAdmin

# 重写UserAdmin类
class UserAdmin(AuthUserAdmin):
    # 添加用户页面可控制字段
    add_fieldsets = (
        (None, {
            'classes': ('wide',),
            
            # 自定义添加用户页面中的可控制字段,可以让密码变成密文
            'fields': ('username', 'password1', 'password2', 'is_staff', 'mobile'),
        }),
    )
    # 自定义用户信息展示页面显示的字段
    list_display = ('username', 'email', 'mobile', 'is_staff')

# 注册自定义User表,用admin管理,配置UserAdmin,定制化管理页面
admin.site.register(models.User, UserAdmin)



# models文件中:

# 重点:通过继承AbstractUser创建的用户管理表,一定要在第一次数据库迁移时完成
from django.db import models
from django.contrib.auth.models import AbstractUser

class User(AbstractUser):
    mobile = models.CharField(max_length=11, verbose_name='电话号码', unique=True)

    # 配置User类
    class Meta:
        
        # 控制数据表创建时的表名直接就是 my_user,没有前缀
        db_table = 'my_user'
        
        # 使用admin后台管理是时显示User表时变为”用户表“(就是汉化)
        verbose_name_plural = '用户表'

    def __str__(self):
        return self.username

三、DRF的三大认证组件概括

  • 共有 认证组件、权限组件、频率组件 三大认证组件

1. 认证组件

  • 就是身份认证,校验用户:游客、合法用户、非法用户

    • 1. 游客:代表校验通过,直接进入下一步校验(权限校验)
      
      2. 合法用户:代表校验通过,将用户存储在request.user中,再进入下一步校验(权限校验)
      
      3. 非法用户:代表校验失败,抛出异常,返回403权限异常结果
      
      4. 只要通过认证不管是游客还是登录用户,request.user都有值

2. 权限组件

  • 校验用户权限:必须是已登录的

    • 1. 针对所有用户——》校验用户的读写权限 。如:游客只读,正规用户可读可写
      
      2. 认证通过:可以进入下一步校验(频率认证)
      
      3. 认证失败:抛出异常,返回403权限异常结果

3. 频率组件

  • 限制视图接口在一定的时间内被访问的频率次数

    • ```python
      1. 限制的条件(IP、id、唯一键)、频率周期时间(s、m、h)、频率的次数(3/s)
    1. 没有达到限次:正常访问接口

    2. 达到限次:限制时间内不能访问,限制时间达到后,可以重新访问
      ```

四、Django中的用户权限管理

  • 一般项目中,采用的是传统的RBAC(Role-BasedAccessControl)。
    
    传统的RBAC有两种:权限三表和权限五表(没有UP关系表)
    
    权限三表:User、Group、Permission表
    权限五表:User、Group、Permission、UG关系表、GP关系表
  • Django中Auth组件采用的是:权限六表(在传统RBAC基础上增加UP关系表)
    
    权限六表:
    User、Group、Permission、UG关系表、UP关系表、GP关系表
    
    ************************************************
    注意:用户管理表(即权限六表),一定要在第一次数据库迁移时完成
    ************************************************

五、jwt认证

  • jwt:json web token
  • jwt是另一种登陆认证的认证方式。
  • 还有一种就是通过在服务端保存session到session表,再将客户端的session值与服务端保存的session值比对完成登陆认证。

1. jwt认证和普通session认证的区别

  • jwt认证的优点:
1)数据库不需要存储token,所以服务器的 IO 操作会减少(没有IO写操作)

2)客户端存Token,服务器只存储签发与校验算法,执行效率高

3)签发与校验算法在多个服务器上可以直接统一,所以jwt认证规则下,服务器做集群非常便捷(服务器集群的意思是可有有多个服务器,token的签发和校验可以再不同的服务器上进行)

2. jwt认证介绍

(1)jwt的原理

  1. jwt由 头.载荷.签名 三部分组成,中间由 点 连接
  2. 上面的三部分的每一部分数据都是一个json字典,头和载荷采用 base64 可逆加密算法加密,签名采用 HS256 不可逆加密

(2)jwt三部分的内容

  • jwt的头
jwt的头部中一般是基本信息(内容也可以为空):公司名称、项目组信息、开发者信息等
  • jwt的载荷
jwt的载荷中一般是核心信息:用户主键、用户账号、客户端设备信息、token的过期时间等
  • jwt的签名
jwt的签名中是安全信息:头的加密结果、载荷的加密结果、服务器的安全码(盐)...

3. jwt的签发算法

  • 共分为4步
  • 注意:只要并且只有在用户重新登录时才会再次签发新的token。若是原token没有超过失效时间,也是有效的。

(1)第一步:头部算法

1. 内容:头内容写死(可以为空{}):公司、项目组信息都是固定不变的

2. 算法:将需要的数据字典转化成json字符串,再将json字符串加密成base64字符串

(2)第二步:载荷部分的算法

1. 内容:用户账号、客户端设备信息是由客户端提供,用户主键是客户端提供账号密码校验User表通过后才能确定,过期时间根据当前时间与配置的过期时间相结合产生

2. 算法:将数据字典转化成json字符串,再将json字符串加密成base64字符串

(3)第三步:签名部分的算法

1. 内容:先将头的加密结果,载荷的加密结果作为成员,再从服务器上拿安全码(不能让任何客户端知道),也可以额外包含载荷的部分(用户信息,设备信息)

2. 算法:将数据字典转化成json字符串,再将json字符串不可逆的加密成HS256字符串

(4)第四步:连接生成token

将前三步产生的三个字符串用 . 连接产生三段式token

4. jwt的校验算法

  • 共分为5步

(1)第一步:切分

从客户端提交的请求中拿到token,用 . 分割成三段(如果不是三段,非法)

(2)第二步:解密头部

# 解密切分后的第一段,即头部

看情况做,一般不需要解密

(3)第三步:解密载荷

# 解密切分的第二段,即载荷部分:

先用base64解密成json字符串,再转换成python格式的字典数据:

    i)用户主键与用户账号查询User表确定用户是否存在
    ii)用本次请求提交的设备信息与解密后的载荷中的设备信息比对,确定前后是否是同一设备,决定是否对用户做安全提示(eg:短信邮箱提示异地登录)(同样的安全保障还可以为IP、登录地点等)
    iii)过期时间与当前时间比对,该token是否在有效时间内

(4)第四步:碰撞校验签名

# 用切分的第三段,即token中的签名部分进行校验

i)将用户最新提交的token中第一段和第二段字符串(即头、载荷加密字符串)和服务端的数据库安全码再组成字典,转换成json格式的字符串
ii)采用不可逆HS256加密对新组成的json字符串加密产生新的签名字符串
iii)新的签名字符串与第三段签名碰撞比对,一致才能确保token是合法的

(5)第五步:校验用户对象

前方算法都通过后,用载荷中的用户主键校验得到的User对象,就是该token代表的登录用户(Django项目一般都会把登录用户存放在request.user中)

5. 刷新算法

(1)什么是刷新算法

  • 刷新算法就是在签发完token后,在token的有效时间内,用户每次提交请求时都会刷新该token的有效时间。但每次刷新后的token有效时间都应该小于一个指定的时间。总而言之:就是说一个token应该有一个指定的有效时间,刷新时间后的有效时间要在该指定的有效时间之内变动,以此来加强token的安全性。

  • 因此需要有一个算法来处理这个逻辑,这就是刷新算法

(2)刷新算法的实现

1)要在签发token的载荷中,额外添加两个时间信息:第一次签发token的时间,最多往后刷新的有效时间
2)每一请求携带token,不仅走校验算法验证token是否合法,还要额外请求刷新token的接口,完成token的刷新:校验规则与校验算法差不多,但是要将过期时间后移(没有超过有效时间,产生新token给客户端,如果超过了,刷新失败,token失效)
3)所以服务器不仅要配置过期时间,还需要配置最长刷新时间(即token最大有效时间)

相关推荐