Django学习之JWT

Stella981
• 阅读 475

JWT

Json Web Token ,是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准(RFC 7519),被设计为紧凑且安全的,特别适用于分布式站点的单点登录(SSO)场景。

单点登录(Single Sign On,以下简称SSO),是指在多系统应用群中登录一个系统,便可在该应用群其他所有系统中得到授权而无需再次登录。

单系统登录(session)认证和单点(token)认证

session 认证

我们知道,http协议本身是一种无状态的协议,而这就意味着如果用户向我们的应用提供了用户名和密码来进行用户认证,那么下一次请求时,用户还要再一次进行用户认证才行,因为根据http协议,我们并不知道是哪个用户发出的请求,所以为了让我们的应用能识别出是哪个用户发出的请求,我们只能在服务器存储一份用户登录的信息,这份登录信息会在响应时传递给浏览器,告诉其保存到Cookie,以便下次请求时发送给我们的应用,这样我们的应用就能识别请求来是自哪个用户。

传统session的问题

开销:用户经过认证后,要在服务端做一次记录,即创建一个session对象,以便用户下次请求的鉴别,通常而言,这个session对象保存在内存中,而随着认证用户的增多,服务器的开销会明显增大。
扩展性(scaling):用户认证之后,服务端做认证记录,如果认证的记录被保存在内存中的话,这就意味着用户下次请求时还必须请求在这台服务器上,这样才能拿到授权的资源,这样在分布式的应用上,相应的限制了负载均衡的能力,同时也限制了跨域认证的问题,也就意味着限制了应用的扩展能力。
CSRF:因为是基于Cookie 来进行用户识别的,所以如果Cookie 被截获,用户很容易受到跨站请求伪造的攻击。

token 的认证

基于token 认证是将验证用户全交给一个单独的认证中心,只有认证中心能接收用户的用户名和密码等安全信息,认证中心验证成功后,创建授权令牌(token),服务器通过令牌,在认证中心校验,通过后才返回给用户受保护资源。

JWT 就是类似于token 的认证的一种实现方式
JWT 的声明一般被用来在身份提供者和服务提供者间传递被认证的用户身份信息,以便于从资源服务器获取受保护资源,也可以增加一些额外的其他业务逻辑所必须的声明信息,该token也可直接被用于认证,也可被加密。

JWT的原理

用户通过服务器认证,生成一个JSON 对象,返回给用户,以后用户与服务器端通信的时候,都要携带这个JSON 对象,服务器完全靠这个对象认定用户身份,为了防止用户篡改数据,服务器端在生成这个JSON 对象的时候,会加上签名,如下图

Django学习之JWT

服务器不再保存任何session 数据,也就是说,服务器变成无状态了,节省服务器开销的同时,使其变得容易实现扩展

JWT的数据构成

JWT 是由三段信息构成,这三段信息用“.”连接,整体就构成了JWT 字符串,如下图:

Django学习之JWT

header

被称为JWT 的头部,主要承载两部分信息
  1.声明类型,比如JWT
  2.声明加密的算法,通常直接使用HMAC SHA256
  完整的头部就像下面的JSON对象:
  {
    “typ”:“JWT”,
    “alg”:“HS256”
  }
  上面JSON 中alg (algorithm)属性表示签名的算法,typ 属性表示这个token 的类型,JWT 类型统一为“JWT”
  然后对这个JSON对象进行Base64URL加密,就构成了JWT的第一部分,header

playload

被称为JWT的载荷,是用来存放实际需要传递的数据
  标准声明(官方字段,建议但不强制使用)
  iss(issuer):JWT签发者
  sub(subject):主题
  aud(audience):接收JWT的一方
  iat(issued at):JWT的签发时间
  exp(expiration time):JWT的过期时间,这个过期时间必须要大于签发时间
  nbf(not before):定义在什么时间之前,该JWT都是不可用的
  jti(jwt id):JWT的唯一身份标识,主要用来作为一次性token,从而回避重放攻击
  其他声明
  除了标准声明中的官方字段,还可以添加部分私有字段,一般添加用户的相关信息或其他业务需要的必要信息,但不建议添加敏感信息,因为该部分在客户端可以解密。
  比如定义一个playload
  {
    “sub”:“123456789”,
    “id”:“6”,
    “name”:“Lucy”
  }
  然后对这个JSON 对象进行Base64URL 加密,就构成了JWT 的第二部分

signature

JWT 的第三部分是一个签证信息,这个签证信息由三部分组成:
  Base64URL 加密后的header
  Base64URL 加密后的payload
  secret
  这个部分需要Base64URL 加密后的header 和Base64URL 加密后的payload 使用“.” 连接组成的字符串,然后通过header 中声明的加密方式进行,如:
  HMACSHA256(base64UrlEncode(header) + '.' + Base64UrlEncode(payload), secret)
  通过加密算出签名后,再把Header、Payload、Signature 三部分拼成通过两个“.” 拼接成一个字符串,就构成了JWT

扩展:Base64URL

这个算法跟Base64 算法基本类似,有一些小不同就是。JWT 作为一个令牌,有些场合可能回放到URL(比如api.example.com/?token=xxx)Base64 有三个字符“+”,“/”,“=”,这三个字符在URL里面有特殊含义,所以要被替换掉:“=”被省略,“+”替换成了“-”,“/”替换成了“_”

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

JWT 的使用方式

客户端收到服务器返回的JWT,可以存储在Cookie 里面,也可以存储在LocalStorage 里面
此后,客户端每次与服务器通信,都要带上这个JWT。可以通过Cookie 里面自动发送,但是这样不能跨域,更好的做法是放在HTTP 请求头信息的"Authorization" 字段里面
另一个做法就是,跨域的时候,JWT 就放在POST请求的数据体里面

JWT 的特点及总结

1.不需要在服务器端保存会话信息,所以易于应用的扩展
2.JWT 的构成非常简单,字节占用很小,所以它是非常便于传输的
3因为有Payload 部分,所iJWT 可以自身存储一些其他业务逻辑所必要的非敏感信息
4.因为JSON 的通用性,所以JWT 是可以进行跨语言支持的,像Java、JavaScript、PHP、Python等很多语言都可以使用
5.JWT 不仅可以用于认证,也可以用于交换信息,有效的使用JWT,可以降低服务器查询数据库的次数
6.JWT 默认是不加密的,但是也可以加密的,生成原始Token 以后,还可以使用密钥再加密一次
7.JWT 不加密的情况下,不能将敏感数据写入JWT
8.JWT 最大的缺点就是,由于服务器不保存session 状态,因此无法再使用过程中废止某个token,或更改token 的权限,也就是说,一旦JWT 签发了,在到期之前就会始终有效,除非服务器额外的处理逻辑。
9.JWT 本身包含了认证信息,一旦泄露,任何人都可以获得该令牌的所有权限,为了减少盗用,JWT 的有效期应该设置得比较短,对于一些比较重要的权限,使用时应该再次对用户进行认证。
10.为了减少盗用,JWT 不应该使用HTTP 协议明码传输,要使用HTTPS 协议传输。

参考:JSON Web Token 入门教程http://www.ruanyifeng.com/blog/2018/07/json\_web\_token-tutorial.html

点赞
收藏
评论区
推荐文章
blmius blmius
2年前
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
Jacquelyn38 Jacquelyn38
2年前
2020年前端实用代码段,为你的工作保驾护航
有空的时候,自己总结了几个代码段,在开发中也经常使用,谢谢。1、使用解构获取json数据let jsonData  id: 1,status: "OK",data: 'a', 'b';let  id, status, data: number   jsonData;console.log(id, status, number )
皕杰报表之UUID
​在我们用皕杰报表工具设计填报报表时,如何在新增行里自动增加id呢?能新增整数排序id吗?目前可以在新增行里自动增加id,但只能用uuid函数增加UUID编码,不能新增整数排序id。uuid函数说明:获取一个UUID,可以在填报表中用来创建数据ID语法:uuid()或uuid(sep)参数说明:sep布尔值,生成的uuid中是否包含分隔符'',缺省为
Easter79 Easter79
2年前
Twitter的分布式自增ID算法snowflake (Java版)
概述分布式系统中,有一些需要使用全局唯一ID的场景,这种时候为了防止ID冲突可以使用36位的UUID,但是UUID有一些缺点,首先他相对比较长,另外UUID一般是无序的。有些时候我们希望能使用一种简单一些的ID,并且希望ID能够按照时间有序生成。而twitter的snowflake解决了这种需求,最初Twitter把存储系统从MySQL迁移
Wesley13 Wesley13
2年前
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
2年前
00:Java简单了解
浅谈Java之概述Java是SUN(StanfordUniversityNetwork),斯坦福大学网络公司)1995年推出的一门高级编程语言。Java是一种面向Internet的编程语言。随着Java技术在web方面的不断成熟,已经成为Web应用程序的首选开发语言。Java是简单易学,完全面向对象,安全可靠,与平台无关的编程语言。
Stella981 Stella981
2年前
Django REST framework JWT学习
1.JWT学习在用户注册或登录后,我们想记录用户的登录状态,或者为用户创建身份认证的凭证。我们不再使用Session认证机制,而使用JsonWebToken认证机制。Jsonwebtoken(JWT),是为了在网络应用环境间传递声明而执行的一种基于JSON的开放标准((RFC7519).该token被设计为紧凑且安全的,
Stella981 Stella981
2年前
Django中Admin中的一些参数配置
设置在列表中显示的字段,id为django模型默认的主键list_display('id','name','sex','profession','email','qq','phone','status','create_time')设置在列表可编辑字段list_editable
Wesley13 Wesley13
2年前
MySQL部分从库上面因为大量的临时表tmp_table造成慢查询
背景描述Time:20190124T00:08:14.70572408:00User@Host:@Id:Schema:sentrymetaLast_errno:0Killed:0Query_time:0.315758Lock_
Python进阶者 Python进阶者
3个月前
Excel中这日期老是出来00:00:00,怎么用Pandas把这个去除
大家好,我是皮皮。一、前言前几天在Python白银交流群【上海新年人】问了一个Pandas数据筛选的问题。问题如下:这日期老是出来00:00:00,怎么把这个去除。二、实现过程后来【论草莓如何成为冻干莓】给了一个思路和代码如下:pd.toexcel之前把这