DRF ~ day10 之 jwt原理解析、jwt开发流程、jwt介绍和快速使用、定制返回格式、自定义用户表,签发

本文主要是介绍DRF ~ day10 之 jwt原理解析、jwt开发流程、jwt介绍和快速使用、定制返回格式、自定义用户表,签发,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

jwt原理解析、jwt开发流程、jwt介绍和快速使用、定制返回格式、自定义用户表,签发


文章目录

  • jwt原理解析、jwt开发流程、jwt介绍和快速使用、定制返回格式、自定义用户表,签发
  • 一、jwt原理解析
    • 1.1、jwt的构成和工作原理
      • 1.1.1、JWT的构成
      • 1.1.2、header (头部)
      • 1.1.2、payload(载荷)
      • 1.1.3、signature(签证)
  • 二、jwt开发流程
  • 三、drf - jwt的快速使用
    • 3.1、jwt的快速使用的两种方法
    • 3.2、jwt的安装
    • 3.3、jwt的签发过程
    • 3.4、jwt的认证过程
  • 四、drf ~ jwt 定制返回格式
  • 五、自定义用户表和签发token
  • 六、drf-jwt自定义认证类
  • 七、drf-jwt的签发源码分析
  • 八、认证权限源码分析
  • 总结


一、jwt原理解析

在用户注册或登录后,我们想记录用户的登录状态,或者为用户创建身份认证的凭证。我们不再使用Session认证机制,而使用Json Web Token(本质就是token)认证机制。

Json web token (JWT), 是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准((RFC 7519).该token被设计为紧凑且安全的,特别适用于分布式站点的单点登录(SSO)场景。JWT的声明一般被用来在身份提供者和服务提供者间传递被认证的用户身份信息,以便于从资源服务器获取资源,也可以增加一些额外的其它业务逻辑所必须的声明信息,该token也可直接被用于认证,也可被加密。

基于session的认证在这里插入图片描述
在这里插入图片描述

基于jwt的认证
在这里插入图片描述
在这里插入图片描述

1.1、jwt的构成和工作原理

1.1.1、JWT的构成

JWT就是一段字符串,由三段信息构成的,将这三段信息文本用.链接一起就构成了Jwt字符串。就像这样:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ

第一部分我们称它为头部(header),第二部分我们称其为载荷(payload, 类似于飞机上承载的物品),第三部分是签证(signature).

1.1.2、header (头部)

jwt的头部承载两部分信息:

  • 声明类型:这里是jwt
  • 声明加密的算法:通常直接使用 HMAC SHA256

完整的头部信息就像下面这样的JSON:

'''
{
'type': 'JWT',
'alg': 'HS256'
}
'''

然后将头部进行base64编码,构成了第一部分。

eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9

1.1.2、payload(载荷)

载荷就是存放有效信息的地方。这个名字像是特指飞机上承载的货品,这些有效信息包含三个部分

  • 标准中注册的声明
  • 公共的声明
  • 私有的声明

标准中注册的声明 (建议但不强制使用) :

  • iss: jwt签发者
  • sub: jwt所面向的用户
  • aud: 接收jwt的一方
  • exp: jwt的过期时间,这个过期时间必须要大于签发时间
  • nbf: 定义在什么时间之前,该jwt都是不可用的.
  • iat: jwt的签发时间
  • jti: jwt的唯一身份标识,主要用来作为一次性token,从而回避时序攻击。

公共的声明 : 公共的声明可以添加任何的信息,一般添加用户的相关信息或其他业务需要的必要信息.但不建议添加敏感信息,因为该部分在客户端可解密.

私有的声明 : 私有声明是提供者和消费者所共同定义的声明,一般不建议存放敏感信息,因为base64是对称解密的,意味着该部分信息可以归类为明文信息。

定义定义一个payload(载荷):

{"exp": "1234567890","name": "John Doe","user_id":99
}

然后将其进行base64编码,得到JWT的第二部分。

eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9

1.1.3、signature(签证)

JWT的第三部分是一个签证信息,这个签证信息由三部分组成:

  • header (base64后的)
  • payload (base64后的)
  • secret

这个部分需要base64加密后的header和base64加密后的payload使用.连接组成的字符串,然后通过header中声明的加密方式进行加盐secret组合加密,然后就构成了jwt的第三部分。

// javascript
var encodedString = base64UrlEncode(header) + '.' + base64UrlEncode(payload);var signature = HMACSHA256(encodedString, 'secret'); // TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ

将这三部分用.连接成一个完整的字符串,构成了最终的jwt:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ

注意:secret是保存在服务器端的,jwt的签发生成也是在服务器端的,secret就是用来进行jwt的签发和jwt的验证,所以,它就是你服务端的私钥,在任何场景都不应该流露出去。一旦客户端得知这个secret, 那就意味着客户端是可以自我签发jwt了。

二、jwt开发流程

使用jwt认证的开发流程,就是两部分

  • 第一部分: 签发token的过程,登录做的
    用户携带用户名和密码,访问我,我们校验通过,生成token串,返回给前端
  • 第二部分:token认证过程,登录认证时使用,其实就是咱们之前讲的认证类,在认证类中完成对token的认证操作
    用户访问我们需要登陆后才能访问的接口,必须携带我们签发的token串(请求头)
    我们取出token,验证该token是否过期,是否被篡改,是否是伪造的
    如果正常,说明荷载中的数据,就是安全的,可以根据荷载中的用户id,查询出当前登录用户,放到request中即可

三、drf - jwt的快速使用

django + drf 框架中,使用jwt来做登录认证

3.1、jwt的快速使用的两种方法

  1. 使用第三方模块
    -django-rest-framework-jwt:https://github.com/jpadilla/django-rest-framework-jwt
    这个是老版本的,已经不维护了,在django框架3.x以上的版本已经不能使用了,只能3.x及以下版本使用

    -djangorestframework-simplejwt:https://github.com/jazzband/djangorestframework-simplejwt
    新的版本

  2. 我们可以自己封装
    参考链接: https://gitee.com/liuqingzheng/rbac_manager/tree/master/libs/lqz_jwt

3.2、jwt的安装

pip安装: pip3.9 install djangorestframework-jwt

3.3、jwt的签发过程

签发过程(是快速签发),必须是auth的user表(这个是别人已经帮您写好了)
写登录接口 -------》 基于auth的user表签发的

  • 路由层代码
from django.contrib import admin
from django.urls import path# 导入jwt签发的模块
from rest_framework_jwt.views import obtain_jwt_tokenurlpatterns = [path('admin/', admin.site.urls),# 这样写签发加登录接口就有了path('login/', obtain_jwt_token),
]
  • 创建超级用户
    在django的tools目录栏点击Run manage.py Task 后的创建创建超级用户
    createsuperuser
    在这里插入图片描述创建前
    在这里插入图片描述创建后
    在这里插入图片描述
  • 创建两个超级用户,密码一样,为什么结果不一样的分析?
    在这里插入图片描述
    补充:
    - 密码明文一样,每次加密后都不一样,如何做,动态加盐,动态的盐要保存,跟密码保存在一起
    - 有代码,有数据库,没有登录不进去的系统
  • postman展示(获取token成功)
    在这里插入图片描述
  • 可以根据返回的token解码出用户信息
import base64# "token":
# "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoxLCJ1c2VybmFtZSI6InJvb3QiLCJleHAiOjE2ODUzNjEwMzksImVtYWlsIjoiIn0.JQr8OajKGCvT5o4QFca2aWKiK20D4KJPTJ6p15K_c8o"# 头部
# res = base64.b64decode('eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9')
# print(res)  # b'{"typ":"JWT","alg":"HS256"}'# 载荷
# res = base64.b64decode('eyJ1c2VyX2lkIjoxLCJ1c2VybmFtZSI6InJvb3QiLCJleHAiOjE2ODUzNjEwMzksImVtYWlsIjoiIn0')
# 需要填充=
res = base64.b64decode('eyJ1c2VyX2lkIjoxLCJ1c2VybmFtZSI6InJvb3QiLCJleHAiOjE2ODUzNjEwMzksImVtYWlsIjoiIn0=')
print(res)   # b'{"user_id":1,"username":"root","exp":1685361039,"email":""}'

按上面的推导token出现了解决不了:
就是:如果token被获取,模拟发送请求,这个是解决不了的
但是:token不能篡改,不能伪造
如何保证token的安全性? 设置token的过期时间

以上代码实现的过程是使用auth的user表做登录,不需要写额外的代码了

3.4、jwt的认证过程

  • 路由层代码
from django.contrib import admin
from django.urls import path
from app01 import views
# 导入jwt签发的模块
from rest_framework_jwt.views import obtain_jwt_tokenurlpatterns = [path('admin/', admin.site.urls),# 这样写签发加登录接口就有了,# 登录接口就有了,并且可以签发token,如果使用auth的user表做登录,不需要写额外的代码了path('login/', obtain_jwt_token),# 写认证的接口path('books/', views.BookView.as_view()),
]
  • 认证类创建认证模块auth.py文件
from rest_framework.authentication import BaseAuthentication
from rest_framework.exceptions import AuthenticationFailedimport jwt
from rest_framework_jwt.settings import api_settings
from .models import Userjwt_decode_handler = api_settings.JWT_DECODE_HANDLERclass JWTAuthentication(BaseAuthentication):def authenticate(self, request):token = request.META.get('HTTP_TOKEN')# 背过# 校验token是否过期,合法,如果都通过,查询出当前用户,返回# 如果不通过,抛异常try:payload = jwt_decode_handler(token)# 如果认证通过,payload就可以认为是安全的,我们就可以使用user_id = payload.get('user_id')# 每个需要登录后,才能访问的接口,都会走这个认证类,一旦走到这个认证类,机会去数据库查询一次数据,会对数据造成压力?user = User.objects.get(pk=user_id)# 优化后的# user = User(username=payload.get('username'), id=user_id)# user = {'username':payload.get('username'), 'id':user_id}except jwt.ExpiredSignature:raise AuthenticationFailed('token过期')except jwt.DecodeError:raise AuthenticationFailed('解码失败')except jwt.InvalidTokenError:raise AuthenticationFailed('token认证异常')except Exception:raise AuthenticationFailed('token认证异常')return user, token
  • 视图层代码
from rest_framework_jwt.authentication import JSONWebTokenAuthentication
from rest_framework.permissions import IsAuthenticated
from rest_framework.views import APIView
from rest_framework.response import Response# 设置必须登录后才能访问
class BookView(APIView):authentication_classes = [JSONWebTokenAuthentication]  # 认证类,drf-jwt提供的permission_classes = [IsAuthenticated]  # 权限类,drf提供的def get(self, request):return Response("你看到我了")
  • postman展示
    在这里插入图片描述

总结:访问的时候,要在请求头中携带,必须叫Authorization:jwt token串
认证规定,请求必须放在请求头中headers中写入
k必须写:Authorization v写:jwt 后加token

四、drf ~ jwt 定制返回格式

设置 登录签发token的接口,要返回code, msg,username, token等信息

对返回格式进行定制
1 写个函数,函数返回字典格式,返回的格式,会被序列化,前端看到
2 写的函数配置一下

新建一个py文件 jwt_response.py 文件

def common_response(token, user=None, request=None):return {'code': '100','msg': '登录成功','username': user.username,'token': token,}

配置文件(settings.py文件中)配置

JWT_AUTH = {'JWT_RESPONSE_PAYLOAD_HANDLER': 'app01.jwt_response.common_response',
}

postman展示
在这里插入图片描述

五、自定义用户表和签发token

  • 模型层代码
from django.db import models# Create your models here.class User(models.Model):username = models.CharField(max_length=32)password = models.CharField(max_length=64)age = models.IntegerField()email = models.CharField(max_length=64)
  • 路由层代码
from django.contrib import admin
from django.urls import path
from app01 import views
# 导入jwt签发的模块
from rest_framework_jwt.views import obtain_jwt_tokenurlpatterns = [path('admin/', admin.site.urls),# 自定义用户表,写接口,做的token签发path('login/', views.UserView.as_view({'post': 'login'})),
]
  • 视图层代码
# 自定义用户表,写登录接口,做token签发from rest_framework.viewsets import ViewSet
from rest_framework.response import Response
from .models import User# 导入签发模块
from rest_framework_jwt.settings import api_settings
jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER
jwt_encode_handler = api_settings.JWT_ENCODE_HANDLERclass UserView(ViewSet):def login(self, request):username = request.data.get('username')password = request.data.get('password')user = User.objects.filter(username=username, password=password).first()if user:# 登录成功,签发token# 签发token# 1、 通过user,获取payloadpayload = jwt_payload_handler(user)print(payload)# 2、通过payload,得到tokentoken = jwt_encode_handler(payload)return Response({'code': 100, 'msg': '登录成功', 'username': user.username, 'token': token})else:return Response({'code': 101, 'msg': '用户名或密码错误'})

*postman展示
在这里插入图片描述

六、drf-jwt自定义认证类

  • 创建认证类的文件auth.py写自定义认证类
from rest_framework.authentication import BaseAuthentication
from rest_framework.exceptions import AuthenticationFailedimport jwt
from rest_framework_jwt.settings import api_settings
from .models import Userjwt_decode_handler = api_settings.JWT_DECODE_HANDLERclass JWTAuthentication(BaseAuthentication):def authenticate(self, request):token = request.META.get('HTTP_TOKEN')# 背过# 校验token是否过期,合法,如果都通过,查询出当前用户,返回# 如果不通过,抛异常try:payload = jwt_decode_handler(token)# 如果认证通过,payload就可以认为是安全的,我们就可以使用user_id = payload.get('user_id')# 每个需要登录后,才能访问的接口,都会走这个认证类,一旦走到这个认证类,机会去数据库查询一次数据,会对数据造成压力?user = User.objects.get(pk=user_id)# 优化后的# user = User(username=payload.get('username'), id=user_id)# user = {'username':payload.get('username'), 'id':user_id}except jwt.ExpiredSignature:raise AuthenticationFailed('token过期')except jwt.DecodeError:raise AuthenticationFailed('解码失败')except jwt.InvalidTokenError:raise AuthenticationFailed('token认证异常')except Exception:raise AuthenticationFailed('token认证异常')return user, token
  • 视图层
from rest_framework.views import APIView
from rest_framework.response import Response
from .auth import JWTAuthenticationclass BookView(APIView):authentication_classes = [JWTAuthentication]def get(self, request):print(request.user.age)return Response("你看到我了")
  • 路由层
    path('books/', views.BookView.as_view()),

postman展示
在这里插入图片描述
这里的token是登录之后返回到前端的token

七、drf-jwt的签发源码分析

# from rest_framework_jwt.views import obtain_jwt_token
# obtain_jwt_token就是ObtainJSONWebToken.as_view()---》视图类.as_view()# 视图类
class ObtainJSONWebToken(JSONWebTokenAPIView):serializer_class = JSONWebTokenSerializer# 父类:JSONWebTokenAPIView
class JSONWebTokenAPIView(APIView):# 局部禁用掉权限和认证permission_classes = ()authentication_classes = ()def post(self, request, *args, **kwargs):# serializer=JSONWebTokenSerializer(data=request.data)serializer = self.get_serializer(data=request.data)# 调用序列化列的is_valid---》字段自己的校验规则,局部钩子和全局钩子# 读JSONWebTokenSerializer的局部或全局钩子if serializer.is_valid(): # 全局钩子在校验用户,生成token# 从序列化类中取出useruser = serializer.object.get('user') or request.user# 从序列化类中取出tokentoken = serializer.object.get('token')# 咱么定制返回格式的时候,写的就是这个函数response_data = jwt_response_payload_handler(token, user, request)response = Response(response_data)return responsereturn Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)# JSONWebTokenSerializer的全局钩子
class JSONWebTokenSerializer(Serializer):def validate(self, attrs):# attrs前端传入的,校验过后的数据 {username:lqz,password:lqz12345}credentials = {'username': attrs.get('usernme'),'password': attrs.get('password')}if all(credentials.values()): # 校验credentials中字典的value值是否都不为空# user=authenticate(username=前端传入的,password=前端传入的)# auth模块的用户名密码认证函数,可以传入用户名密码,去auth的user表中校验用户是否存在# 等同于:User.object.filter(username=username,password=加密后的密码).first()user = authenticate(**credentials)if user:if not user.is_active:msg = _('User account is disabled.')raise serializers.ValidationError(msg)payload = jwt_payload_handler(user)return {'token': jwt_encode_handler(payload),'user': user}else:msg = _('Unable to log in with provided credentials.')raise serializers.ValidationError(msg)else:msg = _('Must include "{username_field}" and "password".')msg = msg.format(username_field=self.username_field)raise serializers.ValidationError(msg)

八、认证权限源码分析

# from rest_framework_jwt.authentication import JSONWebTokenAuthentication
# JSONWebTokenAuthentication
class JSONWebTokenAuthentication(BaseJSONWebTokenAuthentication):def get_jwt_value(self, request):# auth=['jwt','token串']auth = get_authorization_header(request).split()auth_header_prefix = api_settings.JWT_AUTH_HEADER_PREFIX.lower()if not auth:if api_settings.JWT_AUTH_COOKIE:return request.COOKIES.get(api_settings.JWT_AUTH_COOKIE)return Noneif smart_text(auth[0].lower()) != auth_header_prefix:return Noneif len(auth) == 1:msg = _('Invalid Authorization header. No credentials provided.')raise exceptions.AuthenticationFailed(msg)elif len(auth) > 2:msg = _('Invalid Authorization header. Credentials string ''should not contain spaces.')raise exceptions.AuthenticationFailed(msg)return auth[1] # token串# 父类中找:BaseJSONWebTokenAuthentication---》authenticate,找到了
class BaseJSONWebTokenAuthentication(BaseAuthentication):def authenticate(self, request):# 拿到前端传入的token,前端传入的样子是  jwt token串jwt_value = self.get_jwt_value(request)# 如果前端没传,返回None,request.user中就没有当前登录用户# 如果前端没有携带token,也能进入到视图类的方法中执行,控制不住登录用户# 所以咱们才加了个权限类,来做控制if jwt_value is None:return Nonetry: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()# 通过payload拿到当前登录用户user = self.authenticate_credentials(payload)return (user, jwt_value)# 如果用户不携带token,也能认证通过
# 所以我们必须加个权限类来限制class IsAuthenticated(BasePermission):def has_permission(self, request, view):return bool(request.user and request.user.is_authenticated)

总结

以上就是今天要讲的内容,本文仅仅简单介绍了jwt的使用。

这篇关于DRF ~ day10 之 jwt原理解析、jwt开发流程、jwt介绍和快速使用、定制返回格式、自定义用户表,签发的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/314340

相关文章

网页解析 lxml 库--实战

lxml库使用流程 lxml 是 Python 的第三方解析库,完全使用 Python 语言编写,它对 XPath表达式提供了良好的支 持,因此能够了高效地解析 HTML/XML 文档。本节讲解如何通过 lxml 库解析 HTML 文档。 pip install lxml lxm| 库提供了一个 etree 模块,该模块专门用来解析 HTML/XML 文档,下面来介绍一下 lxml 库

Security OAuth2 单点登录流程

单点登录(英语:Single sign-on,缩写为 SSO),又译为单一签入,一种对于许多相互关连,但是又是各自独立的软件系统,提供访问控制的属性。当拥有这项属性时,当用户登录时,就可以获取所有系统的访问权限,不用对每个单一系统都逐一登录。这项功能通常是以轻型目录访问协议(LDAP)来实现,在服务器上会将用户信息存储到LDAP数据库中。相同的,单一注销(single sign-off)就是指

Spring Security基于数据库验证流程详解

Spring Security 校验流程图 相关解释说明(认真看哦) AbstractAuthenticationProcessingFilter 抽象类 /*** 调用 #requiresAuthentication(HttpServletRequest, HttpServletResponse) 决定是否需要进行验证操作。* 如果需要验证,则会调用 #attemptAuthentica

这15个Vue指令,让你的项目开发爽到爆

1. V-Hotkey 仓库地址: github.com/Dafrok/v-ho… Demo: 戳这里 https://dafrok.github.io/v-hotkey 安装: npm install --save v-hotkey 这个指令可以给组件绑定一个或多个快捷键。你想要通过按下 Escape 键后隐藏某个组件,按住 Control 和回车键再显示它吗?小菜一碟: <template

性能测试介绍

性能测试是一种测试方法,旨在评估系统、应用程序或组件在现实场景中的性能表现和可靠性。它通常用于衡量系统在不同负载条件下的响应时间、吞吐量、资源利用率、稳定性和可扩展性等关键指标。 为什么要进行性能测试 通过性能测试,可以确定系统是否能够满足预期的性能要求,找出性能瓶颈和潜在的问题,并进行优化和调整。 发现性能瓶颈:性能测试可以帮助发现系统的性能瓶颈,即系统在高负载或高并发情况下可能出现的问题

中文分词jieba库的使用与实景应用(一)

知识星球:https://articles.zsxq.com/id_fxvgc803qmr2.html 目录 一.定义: 精确模式(默认模式): 全模式: 搜索引擎模式: paddle 模式(基于深度学习的分词模式): 二 自定义词典 三.文本解析   调整词出现的频率 四. 关键词提取 A. 基于TF-IDF算法的关键词提取 B. 基于TextRank算法的关键词提取

水位雨量在线监测系统概述及应用介绍

在当今社会,随着科技的飞速发展,各种智能监测系统已成为保障公共安全、促进资源管理和环境保护的重要工具。其中,水位雨量在线监测系统作为自然灾害预警、水资源管理及水利工程运行的关键技术,其重要性不言而喻。 一、水位雨量在线监测系统的基本原理 水位雨量在线监测系统主要由数据采集单元、数据传输网络、数据处理中心及用户终端四大部分构成,形成了一个完整的闭环系统。 数据采集单元:这是系统的“眼睛”,

Hadoop企业开发案例调优场景

需求 (1)需求:从1G数据中,统计每个单词出现次数。服务器3台,每台配置4G内存,4核CPU,4线程。 (2)需求分析: 1G / 128m = 8个MapTask;1个ReduceTask;1个mrAppMaster 平均每个节点运行10个 / 3台 ≈ 3个任务(4    3    3) HDFS参数调优 (1)修改:hadoop-env.sh export HDFS_NAMENOD

使用SecondaryNameNode恢复NameNode的数据

1)需求: NameNode进程挂了并且存储的数据也丢失了,如何恢复NameNode 此种方式恢复的数据可能存在小部分数据的丢失。 2)故障模拟 (1)kill -9 NameNode进程 [lytfly@hadoop102 current]$ kill -9 19886 (2)删除NameNode存储的数据(/opt/module/hadoop-3.1.4/data/tmp/dfs/na

Hadoop数据压缩使用介绍

一、压缩原则 (1)运算密集型的Job,少用压缩 (2)IO密集型的Job,多用压缩 二、压缩算法比较 三、压缩位置选择 四、压缩参数配置 1)为了支持多种压缩/解压缩算法,Hadoop引入了编码/解码器 2)要在Hadoop中启用压缩,可以配置如下参数