JWT验证

算法寻星家
• 阅读 5684

JWT(Json Web Token):是目前最流行的跨域身份验证解决方案。
此前我们使用的身份验证方式都是基于Session:
JWT验证
这种方式并没有什么不妥,但其实这里有三个缺点:

  1. Session一般存储在redis中,而redis数据保存在内存中,随着用户的增多,内存消耗太大。
  2. 扩展性不好,用户每次验证都需要请求session服务器,增大了负载均衡能力,应用扩展受限。
  3. 因为是基于cookie来进行用户识别的, cookie如果被截获,用户就会很容易受到跨站请求伪造的攻击。

所以,我们需要一种既能实现相同要求并且还要比session存储更有效的身份验证方式。

JWT验证
JWT通过一种加密的方式,将加密后的数据保存返回给用户本地进行保存,我们称为token数据。其数据由三部分组成:

1、header声明类型和加密的算法:

{
  'typ': 'JWT',    #固定值
  'alg': 'HS256'    #加密算法
}

2、payload负载
这是有效信息的存放地方,其分为三部分:标准中注册的声明、公共声明、私有声明(用户信息)
标准中的注册声明(有需要在使用,不强制使用):
iss: jwt签发者
sub: jwt所面向的用户
aud: 接收jwt的一方
exp: jwt的过期时间,这个过期时间必须要大于签发时间
nbf: 定义在什么时间之前,该jwt都是不可用的.
iat: jwt的签发时间
jti: jwt的唯一身份标识,主要用来作为一次性token,从而回避重放攻击。
公共声明:公共的声明可以添加任何的信息,一般添加用户的相关信息或其他业务需要的必要信息.
私有声明:

{
  "name": "jim",
  "id": "111111",
  "admin": true
}

3、signature签名
需要base64加密后的header和base64加密后的payload使用.连接组成的字符串,然后通过header中声明的加密方式进行加盐secret组合加密,然后就构成了jwt的第三部分。由于base64是对称加密算法,所以可以轻松解密:因此我们在负载部分不要将私密信息放置在里面,只需要把能验证唯一的标识信息添加就可以了。
有关base64,请参考:https://www.liaoxuefeng.com/w...
由于目前在学习DRF,所以我介绍一下怎样在DRF项目中使用JWT进行身份验证:
安装djangorestframework-jwt:

pip install djangorestframework-jwt

添加jwt认证类:

REST_FRAMEWORK = {
    'DEFAULT_PERMISSION_CLASSES': (
        'rest_framework.permissions.IsAuthenticated',
    ),
    'DEFAULT_AUTHENTICATION_CLASSES': (
        'rest_framework_jwt.authentication.JSONWebTokenAuthentication',
        'rest_framework.authentication.SessionAuthentication',
        'rest_framework.authentication.BasicAuthentication',
    ),
}

添加jwt路由用于生成token:

from rest_framework_jwt.views import obtain_jwt_token

urlpatterns = [
    url(r'^自己的路由/', obtain_jwt_token),
]

然后我们就可以通过自己添加的路由并通过post添加username和password来获取到token了,在进行访问页面的时候我们只需要在请求头中添加一个:Authorization: JWT <your_token>,就可以得到验证了。
当然我们可能不止只需要token数据,还需要用户的ID,昵称等信息,那么我们就需要手动生成token数据。

from rest_framework_jwt.settings import api_settings
    
    jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER
    jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER
    
    payload = jwt_payload_handler(user)    #这里的用户对象就是在登录视图中获取到的user
    token = jwt_encode_handler(payload)

当然我们前面已经说明payload中最好不要存储私密信息,所以我们在处理user前需要将不需要的字段删除:

del user.set_password('')    #当然这样做肯定不科学,但是我们由于这里没有场景,所以我先这样做,有需要的同学可以私聊我。

然后我们可以将返回到前端的数据进行保存,方便下次访问携带:
前端响应中使用的代码格式
关于session和local存储:https://www.cnblogs.com/st-le...

sessionStorage.变量名 = 变量值   // 保存数据
sessionStorage.变量名  // 读取数据
sessionStorage.clear()  // 清除所有sessionStorage保存的数据

localStorage.变量名 = 变量值   // 保存数据
localStorage.变量名  // 读取数据
localStorage.clear()  // 清除所有localStorage保存的数据

最后利用localStorage与sessionStorage读取数据的方式在需要后端验证的地方添加token数据。
所有配置参考:

JWT_AUTH = {
    'JWT_ENCODE_HANDLER':
    'rest_framework_jwt.utils.jwt_encode_handler',    #加密处理函数

    'JWT_DECODE_HANDLER':
    'rest_framework_jwt.utils.jwt_decode_handler',    #解密处理函数

    'JWT_PAYLOAD_HANDLER':
    'rest_framework_jwt.utils.jwt_payload_handler',    #指定自定义函数以生成令牌有效内容

    'JWT_PAYLOAD_GET_USER_ID_HANDLER':
    'rest_framework_jwt.utils.jwt_get_user_id_from_payload_handler',    #如果您的存储username方式与默认的有效负载处理程序不同,请实现此功能以username从有效负载中获取

    'JWT_RESPONSE_PAYLOAD_HANDLER':        #负责控制登录或刷新后返回的响应数据。覆盖以返回自定义响应
    'rest_framework_jwt.utils.jwt_response_payload_handler',

    'JWT_SECRET_KEY': settings.SECRET_KEY,    #使用系统全局的SECRET_KEY
    'JWT_GET_USER_SECRET_KEY': None,    #这是JWT_SECRET_KEY的更强大版本。它是根据用户定义的,因此如果令牌被泄露,可以由所有者轻松更改。更改此值将使给定用户的所有令牌都无法使用。值应该是一个函数,接受用户作为唯一参数并返回它的密钥。
    'JWT_PUBLIC_KEY': None,
    'JWT_PRIVATE_KEY': None,
    'JWT_ALGORITHM': 'HS256',    #加密算法,必须设置为一个RS256,RS384或RS512。
    'JWT_VERIFY': True,
    'JWT_VERIFY_EXPIRATION': True,
    'JWT_LEEWAY': 0,
    'JWT_EXPIRATION_DELTA': datetime.timedelta(seconds=300),    #设置有效期
    'JWT_AUDIENCE': None,
    'JWT_ISSUER': None,    #这是一个字符串,将根据iss令牌字段进行检查。默认是None(不要检查issJWT)
    'JWT_ALLOW_REFRESH': False,
    'JWT_REFRESH_EXPIRATION_DELTA': datetime.timedelta(days=7),    #设置令牌刷新时间,默认为datetime.timedelta(days=7)(7天)

    'JWT_AUTH_HEADER_PREFIX': 'JWT',    #您可以修改需要与令牌一起发送的Authorization标头值前缀。默认值为JWT,用于令牌和授权标头的另一个常见值是Bearer。

    'JWT_AUTH_COOKIE': None,    #验证Authorization标头同时也验证cookie,一般不用

}

本文参考:https://lion1ou.win/2017/01/18/

点赞
收藏
评论区
推荐文章
blmius blmius
4年前
MySQL:[Err] 1292 - Incorrect datetime value: ‘0000-00-00 00:00:00‘ for column ‘CREATE_TIME‘ at row 1
文章目录问题用navicat导入数据时,报错:原因这是因为当前的MySQL不支持datetime为0的情况。解决修改sql\mode:sql\mode:SQLMode定义了MySQL应支持的SQL语法、数据校验等,这样可以更容易地在不同的环境中使用MySQL。全局s
Wesley13 Wesley13
3年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
美凌格栋栋酱 美凌格栋栋酱
7个月前
Oracle 分组与拼接字符串同时使用
SELECTT.,ROWNUMIDFROM(SELECTT.EMPLID,T.NAME,T.BU,T.REALDEPART,T.FORMATDATE,SUM(T.S0)S0,MAX(UPDATETIME)CREATETIME,LISTAGG(TOCHAR(
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
Jacquelyn38 Jacquelyn38
4年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
Easter79 Easter79
3年前
Twitter的分布式自增ID算法snowflake (Java版)
概述分布式系统中,有一些需要使用全局唯一ID的场景,这种时候为了防止ID冲突可以使用36位的UUID,但是UUID有一些缺点,首先他相对比较长,另外UUID一般是无序的。有些时候我们希望能使用一种简单一些的ID,并且希望ID能够按照时间有序生成。而twitter的snowflake解决了这种需求,最初Twitter把存储系统从MySQL迁移
Wesley13 Wesley13
3年前
mysql设置时区
mysql设置时区mysql\_query("SETtime\_zone'8:00'")ordie('时区设置失败,请联系管理员!');中国在东8区所以加8方法二:selectcount(user\_id)asdevice,CONVERT\_TZ(FROM\_UNIXTIME(reg\_time),'08:00','0
Wesley13 Wesley13
3年前
00:Java简单了解
浅谈Java之概述Java是SUN(StanfordUniversityNetwork),斯坦福大学网络公司)1995年推出的一门高级编程语言。Java是一种面向Internet的编程语言。随着Java技术在web方面的不断成熟,已经成为Web应用程序的首选开发语言。Java是简单易学,完全面向对象,安全可靠,与平台无关的编程语言。
Stella981 Stella981
3年前
JSON Web Token 入门教程
JWT是什么?JSONWebToken(缩写JWT)是目前最流行的跨域认证解决方案。它是有三部分组成,示例如下,具体的讲解如下(jwt是不会有空行的,下面只是为了显示,便使用了换行看着比较方便)。1.eyJhbGciOiJIUzI1NiIsInR5cCI6I
Stella981 Stella981
3年前
Django中Admin中的一些参数配置
设置在列表中显示的字段,id为django模型默认的主键list_display('id','name','sex','profession','email','qq','phone','status','create_time')设置在列表可编辑字段list_editable
Python进阶者 Python进阶者
1年前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这