rbac介绍、自动生成接口文档、jwt介绍与快速签发认证、jwt定制返回格式

今日内容概要

  • RBAC
  • 自动生成接口文档
  • jwt介绍与快速使用
  • jwt定制返回格式
  • jwt源码分析

内容详细

1、RBAC(重要)

# RBAC 是基于角色的访问控制(Role-Based Access Control )
	在 RBAC  中,权限与角色相关联,用户通过成为适当角色的成员而得到这些角色的权限。这就极大地简化了权限的管理。这样管理都是层级相互依赖的,权限赋予给角色,而把角色又赋予用户,这样的权限设计很清楚,管理起来很方便。
    
# 对外的权限比较简单:
	普通注册用户,VIP用户,超级VIP  --》优酷,网易云音乐,百度网盘
    
# 公司内部系统:通常使用RBAC的权限控制
	公司内有部门(开发部,运维部,市场部,总裁办,人力资源部门)
	权限和角色(部门)绑定   
    
	举个例子:发工资权限,招人权限,开发代码权限...
		招人权限,发工资权限给人力资源
		开发代码权限给开发部门
        
# 权限赋予给角色(部门),又把角色(部门)又赋予用户

"""
python用来做公司内部项目居多:
	人事系统,进销存,报销审批,自动化运维
	
原因:
	公司内部项目对执行效率要求不高(人少)
	对开发效率要求高(越快开发出越好,成本越低越好)
	知乎,豆瓣用python写的---》随着用户量增大---》切换语言
"""

# 针对于公司内部项目,后台管理居多(运营在使用),使用rbac居多
	django-vue-admin:后端用drf,前端用vue,权限管理的 脚手架---》前后端分离

	django的admin---》混合的后台管理用的多---》基于django的admin二次开发

	simpleui:对django admin的美化

# django的admin自带rbac权限管理(表设计完成权限管理)---》6张表
	用户表
	角色表(组表,部门表)
	权限表

	角色和权限 >>> 多对多中间表
	用户和角色 >>> 多对多中间表
    
	django-admin中多了一张表:
		用户对权限 >>>  多对多中间表
        
"""
在关系型数据库的关系中:只有三种---》本质只有一种:外键关系
	一对多
	多对多
	一对一
"""

### 基于django的admin做二次开发,开发出公司内部的管理系统
	1、纯基于原生
  	
	2、使用第三方美化:
		xadmin(早就不维护了,弃坑了)
		simpleui(国内的,主流),国外也有很多

image

django-admin演示

# 先创建超级用户


# 在models.py 创建表:
from django.db import models

class Book(models.Model):
    name = models.CharField(max_length=32)
    price = models.IntegerField()
    author = models.CharField(max_length=32)

    def __str__(self):
        return self.name
    
    class Meta:
        verbose_name = '图书表'
        verbose_name_plural = '图书表'

        
# 在admin.py中 注册表
from django.contrib import admin
from .models import Book

class BookAdmin(admin.ModelAdmin):
    # 设置列表可显示的字段
    list_display = ('name', 'author',  'price')
    
    # 设置过滤选项
    list_filter = ('name', 'price', )

admin.site.register(Book, BookAdmin)


# 可以修改配置文件为中文显示:

LANGUAGE_CODE = 'zh-hans'

TIME_ZONE = 'Asia/Shanghai'

USE_I18N = True

USE_L10N = True

USE_TZ = False

image

image

2、自动生成接口文档

# 顺利的写接口
	在公司里,前端和后端是两拨人写---》咱们后端接口写好了,我们知道接口怎么用
    
# 后端人,需要写出接口文档,给前端用,前端按照接口文档去开发
# 具体格式可以参照:https://open.weibo.com/wiki/2/comments/show


# 如何写?
	第一种:使用word或者md文档编写---》纯手写---》好的公司这么用
    
	第二种:第三方平台录入---》半手写
		https://blog.csdn.net/weixin_44337261/article/details/121005675-->部分公司
            
	第三种:公司自己开发接口平台,搭建接口平台--》数据放在公司自己--》学长公司在用
		https://zhuanlan.zhihu.com/p/366025001
      
	第四种:自动生成接口文档---》用的少---》自动生成+导出---》录入到yapi
		drf中有两个模块:coreapi,swagger
        
        
### coreapi使用
	第一步:下载 
		pip3 install coreapi

	第二步:修改路由
from rest_framework.documentation import include_docs_urls

# 接口文档
router.register('books2', views.BookListCreateView, 'books2')  # 自动生成路由类的配置
urlpatterns = [
        ...
        path('docs/', include_docs_urls(title='站点页面标题')),
    ]

	第三步:写视图类,只需要加注释即可
from rest_framework.generics import ListCreateAPIView

class BookListCreateView(ViewSetMixin, ListCreateAPIView):
    serializer_class = BookSerializer
    queryset = Book.objects.all()
    """
    get:
    返回所有图书信息.
    post:
    新建图书.
    """

from rest_framework import mixins

class BookInfoViewSet(mixins.ListModelMixin, mixins.RetrieveModelMixin, GenericViewSet):
    """
    list:
    返回图书列表数据

    retrieve:
    返回图书详情数据

    latest:
    返回最新的图书数据

    read:
    修改图书的阅读量
    """
    
	第四步:配置文件中
REST_FRAMEWORK = {
    ...
    # 接口文档配置
    'DEFAULT_SCHEMA_CLASS': 'rest_framework.schemas.coreapi.AutoSchema',
}

image

3、jwt介绍和快速使用

# cookie,session,token的区别?
	https://www.cnblogs.com/liuqingzheng/articles/8990027.html
        
# 认证:session机制:需要在后端存储数据
	之前使用的django-session:
		如果登录用户很多,需要在后端存很多数据,频繁查询数据库,导致效率低
		能不能想一种方案,不在服务端存数据 在客户端存数据(数据安全)---》token认证机制
        
# Json web token (JWT),token是一种认证机制,用在web开发方向,叫 jwt

# JWT的构成
	三段式---每一段都使用 base64编码
	典型的jwt串样子,通过. 分隔成三段:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ
		第一段:头:声明类型,这里是jwt,声明加密的算法,公司信息等等(目前作用不大)
    
		第二段:荷载(payload):有效信息
			用户名,用户id,登陆时间,token失效时间...
        
		第三段:签名(signature):通过  头+荷载 使用某种加密方式加密后得到的


## jwt的签发和认证--保证安全

# 签发
	登陆过程 如果没有第三方模块帮助我们做,我们就自己做
	1)用基本信息公司信息存储json字典,采用base64算法得到 头字符串
    
	2)用关键信息存储json字典,采用base64算法得到 荷载字符串,过期时间,用户id,用户名
    
	3)用头、体加密字符串通过加密算法+秘钥加密得到 签名字符串 拼接成token返回给前台



# 认证
	访问需要登陆的接口
	1)将token按 . 拆分为三段字符串,第一段 头加密字符串 一般不需要做任何处理
    
	2)第二段 体加密字符串,要反解出用户主键,通过主键从User表中就能得到登录用户,过期时间是安全信息,确保token没过期
    
	3)再用 第一段 + 第二段 + 加密方式和秘钥得到一个加密串,与第三段 签名字符串 进行比较,通过后才能代表第二段校验得到的user对象就是合法的登录用户
      
        
# 大部分的web框架都会有第三方模块支持----》如果没有需要自己写
	django中有一个django-rest-framework-jwt,咱们讲的:
	https://github.com/jpadilla/django-rest-framework-jwt
        
	django中还有一个,django-rest-framework-simplejwt,咱们不讲,公司可能会用:
	https://github.com/jazzband/djangorestframework-simplejwt

# 区别
	https://blog.csdn.net/lady_killer9/article/details/103075076

3.1、base64编码和解码

# base64编码和解码
	只是编码和解码,不能叫加密

## 案例:
import base64

# 编码
# s = b'''{"name":"lqz","age":19}'''
# res = base64.b64encode(s)
# print(res)  # eyJuYW1lIjoibHF6IiwiYWdlIjoxOX0=

# 解码
# s = b'eyJuYW1lIjoibHF6IiwiYWdlIjoxOX0='
# res = base64.b64decode(s)
# print(res)  # {"name":"lqz","age":19}


### base64长度必须是4的倍数,如果不够,使用 = 补齐,所以base64编码,最后面可能有 =

### base64 用途在哪?
	对网络传输中的数据进行编码---->jwt,有些图片,使用base64编码(12306)

3.2、django中快速使用jwt

3.2.1、签发

# 第一步:下载模块
	pip3 install djangorestframework-jwt

# 第二步:在路由中配置
from rest_framework_jwt.views import obtain_jwt_token

urlpatterns = [
    # jwt签发
    path('login/', obtain_jwt_token),
]

# 第三步:使用接口测试工具发送post请求到后端,就能基于auth的user表签发token
{
    "token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoyLCJ1c2VybmFtZSI6InB5eSIsImV4cCI6MTY0OTMxNjc3MiwiZW1haWwiOiIzMDYzMzQ2NzhAcXEuY29tIn0.YOUc9gcFIQf9FBibZJANaI3Rmpw4zfMy1e8ez1roKSI"
}


# 比session优势在不需要在后端存数据了,jwt不会在后端存数据,保证了数据安全

### 会有被别人窃取的风险----》只能拿到和使用---》避免不了窃取后使用,只能避免别人篡改不了
	爬虫就是干这事,扣除token串,模拟发请求----》如果你能想一种方式,避免别人获取了token串,不能发请求---》你就把整个爬虫行业干掉了

3.2.2、认证

# 视图类的某个方法,访问时候,需要认证通过才能访问
	写认证类-->我们用了第三方模块---》第三方模块写了一个认证类
    
# 以获取所有图书接口为例
	在视图类中配置:认证类+权限类
from rest_framework_jwt.authentication import JSONWebTokenAuthentication
from rest_framework.permissions import IsAuthenticated

class BookView(GenericViewSet, ListModelMixin):
    '''
    返回所有图书信息
    '''

    queryset = Book.objects.all()
    serializer_class = BookSerializer

    filter_backends = [SearchFilter]
    search_fields = ['name', 'author']  # 过滤

    pagination_class = CommonCursorPagination  # 验证此类分页时 视图类中不可以带有排序功能 要注释掉

    # JSONWebTokenAuthentication 就是 rest_framework_jwt模块写的认证类
    authentication_classes = [JSONWebTokenAuthentication, ]  # 登录认证
    # 需要配合一个权限类
    permission_classes = [IsAuthenticated, ]
    
    
    
### 在前端使用的时候,要携带token
	token携带方式:在请求头中使用  Authorization : jwt token串
        
	为什么要按这个格式?
		人家的认证类已经写完了,就是去请求头中取的,按固定规则取的,所以咱们需要按照这个格式

4、jwt定制返回格式

# 签发token,其实就是jwt模块基于auth的user表,帮咱们写了一个登陆功能,但是一般请求,在我们登陆成功后,返回的数据更多 
	{code:100,msg:登陆成功,token:adfadf,username:pyy}
    
    
# 定义签发token(登陆接口)返回格式
	第一步:写一个函数(新建 utils.py文件)--->返回什么格式,前端就能看到什么格式
def jwt_response_payload_handler(token, user=None, request=None):
    return {
        'code': 100,
        'msg': "登陆成功",
        'token': token,
        'username': user.username
    }

	第二步:在配置文件中配置(不配置就会使用 JWT默认的格式)
# jwt模块的配置文件,统一放在JWT_AUTH
JWT_AUTH = {
    'JWT_RESPONSE_PAYLOAD_HANDLER': 'app01.utils.jwt_response_payload_handler',
}

image

5、jwt源码分析

# 签发源码
	obtain_jwt_token---》ObtainJSONWebToken.as_view():视图类.as_view()
	ObtainJSONWebToken视图类---》登陆post请求,携带用户名密码---》视图类中有post方法
    
# 视图类中的序列化类: 
	serializer_class = JSONWebTokenSerializer---》全局钩子中获取当前登录用户和签发token

# post方法中:
	serializer = self.get_serializer(data=request.data)


### 你会的:
	obtain_jwt_token---》ObtainJSONWebToken视图类---》post方法--》通过前端传入的用户名和密码拿到了当前用户,通过当前用户签发了token---》返回给了前端


# 认证源码
	认证类---》authenticate方法---》验证
    def authenticate(self, request):
        jwt_value = self.get_jwt_value(request)  # 获取真正的token,三段式
        if jwt_value is None:  # 如果没传token,就不认证了,直接通过,所以需要配合权限类一起用
            return None

        try:
            payload = jwt_decode_handler(jwt_value)  # 验证签名
        except jwt.ExpiredSignature:
            msg = _('Signature has expired.')  # 过期了
            raise exceptions.AuthenticationFailed(msg)
        except jwt.DecodeError:
            msg = _('Error decoding signature.')  # 被篡改了
            raise exceptions.AuthenticationFailed(msg)
        except jwt.InvalidTokenError:
            raise exceptions.AuthenticationFailed()  # 不知名的错误

        user = self.authenticate_credentials(payload)

        return (user, jwt_value)
posted @ 2022-04-08 17:31  Deity_JGX  阅读(372)  评论(0编辑  收藏  举报