什么是JWT


目的

了解JWT到底是什么,有什么作用。

前言

我们访问一个网站的时候一般都需要做一些安全认证,防止黑客恶意攻击网站。这个认证的方式有多种,JWT就是其中一种。

安全认证方式

密码认证

这是最低级的认证方式。每次请求都带上用户名和密码,服务端通过校验用户名和密码就能确定当前请求是否合法,但是这需要将用户名和密码告诉发送请求方,造成密码泄露,很容易被其他人拿到,显然是非常不安全的。一般很少用这种方式。

session认证

众所周知,http协议本身是无状态的协议,那就意味着当有用户向系统使用账户名称和密码进行用户认证之后,下一次请求还要再一次用户认证才行。因为我们不能通过http协议知道是哪个用户发出的请求,所以如果要知道是哪个用户发出的请求,那就需要在服务器保存一份用户信息(保存至session),然后在认证成功后返回cookie值传递给浏览器,那么用户在下一次请求时就可以带上cookie值,服务器就可以识别是哪个用户发送的请求,是否已认证,是否登录过期等等。这就是传统的session认证方式。

session认证的缺点其实很明显,由于session是保存在服务器里,所以如果分布式部署应用的话,会出现session不能共享的问题,很难扩展。于是乎为了解决session共享的问题,又引入了redis,接着往下看。

token认证

这种方式跟session的方式流程差不多,不同的地方在于保存的是一个token值到redis,token一般是一串随机的字符(比如UUID),value一般是用户ID,并且设置一个过期时间。每次请求服务的时候带上token在请求头,后端接收到token则根据token查一下redis是否存在,如果存在则表示用户已认证,如果token不存在则跳到登录界面让用户重新登录,登录成功后返回一个token值给。

优点是多台服务器都是使用redis来存取token,不存在不共享的问题,所以容易扩展。缺点是每次请求都需要查一下redis,会造成redis的压力,还有增加了请求的耗时,每个已登录的用户都要保存一个token在redis,也会消耗redis的存储空间。

其实token就是把session保存在redis中。

JWT认证

WT(全称:Json Web Token)是一个开放标准(RFC 7519),它定义了一种紧凑的、自包含的方式,用于作为JSON对象在各方之间安全地传输信息。该信息可以被验证和信任,因为它是数字签名的。

上面说法比较文绉绉,简单点说就是一种认证机制,让后台知道该请求是来自于受信的客户端。

详细介绍JWT

JWT 流程图

JWT生成步骤

  • 用户使用账号、密码登录应用,登录的请求发送到Authentication Server。
  • Authentication Server进行用户验证,然后创建JWT字符串返回给客户端。
  • 客户端请求接口时,在请求头带上JWT。
  • Application Server验证JWT合法性,如果合法则继续调用应用接口返回结果。

可以看出与token方式有一些不同的地方,就是不需要依赖redis,用户信息存储在客户端。所以关键在于生成JWT,和解析JWT这两个地方。

JWT数据结构

WT一般是这样一个字符串,分为三个部分,以”.”隔开:

xxxxx.yyyyy.zzzzz

JWT第一部分是头部分,它是一个描述JWT元数据的Json对象。例如

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9

base64在线解析工具解析结构如下:

{"alg":"HS256","typ":"JWT"}

alg属性表示签名使用的算法,默认为HMAC SHA256(写为HS256),typ属性表示令牌的类型,JWT令牌统一写为JWT。

由此可见header是直接使用base64URL压缩的,没有加密,任何人得到它都可以解析出来。base64URL和base64有什么区别?base64URL会把=解析成%3D,因为要把它放在url中,不能包含=

Payload

WT第二部分是Payload,也是一个Json对象,除了包含需要传递的数据,还有七个默认的字段供选择。

分别是,iss:发行人、exp:到期时间、sub:主题、aud:用户、nbf:在此之前不可用、iat:发布时间、jti:JWT ID用于标识该JWT。

需要注意的是,默认情况下JWT是未加密的,任何人都可以解读其内容,因此如果一些敏感信息不要存放在此,以防信息泄露。

JSON对象也使用Base64 URL算法转换为字符串保存。例如

eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9

解析之后为

{"sub":"1234567890","name":"John Doe","admin":true}

Signature

JWT第三部分是签名。是这样生成的,首先需要指定一个secret,该secret仅仅保存在服务器中,保证不能让其他用户知道。然后使用Header指定的算法对Header和Payload进行计算,然后就得出一个签名哈希。也就是Signature。

那么Application Server如何进行验证呢?可以利用JWT前两段,用同一套哈希算法和同一个secret计算一个签名值,然后把计算出来的签名值和收到的JWT第三段比较,如果相同则认证通过。

应用服务和认证服务之间是内部服务的关系,可以直接共享秘钥或者直接写死用同一个字符串作为秘钥也可以,这样应用服务鉴权的时候就无需任何通信和存储,仅仅通过JWT字符串就可以完成鉴权和获取用户信息,知道当前请求属于哪个用户的。

JWT优点

  • json格式的通用性,所以JWT可以跨语言支持,比如Java、JavaScript、PHP、Node等等。
  • 可以利用Payload存储一些非敏感的信息。
  • 便于传输,JWT结构简单,字节占用小。
  • 不需要在服务端保存会话信息,易于应用的扩展。

JWT和token的区别

token的验证机制流程

  • 1.用户输入账户和密码请求服务器
  • 2.服务器验证用户信息,返回用户一个token值
  • 3.客户端存储token值,在每次请求都提交token值
  • 4.服务器根据token验证用户信息,验证通过后返回请求结果
  • 5.token必须要在每次请求时传递给服务端,都保存在header中

缺点:

  • 1.内存级别重启全部失效。不过可以把token保存在redis中,但是如果redis重启那token也将失效。
  • 2.时效性,无法失效,被非法获取之后可以一直使用。token跟session一样,仅仅是一个字符串,其他的重要信息保存在服务器端,跟token一一对应。它本身不带有时效信息,有效期是保存在服务端的。可以删除服务端保存的token信息来让它失效。
  • 3.集群部署,多台服务器无法共享,在负载会导致用户状态不同步。当然,这个可以通过redis共享token来解决。

JWT特点

  • 1.JWT生成的token是无状态的,服务端不存储,即一旦生成在有效期之前一直可用,无法销毁。返回给用户后,服务端没有任何地方会保存jwt。
  • 2.如果需要刷新token有效期或者提前失效需要借助缓存、数据库或者redis来自己实现对应逻辑。
  • 3.JWT无状态=>不需要通过存储验证是否正确,本身可以验证。
  • 4.手动销毁:必须借助于第三方类似黑名单的方式=> 把检测到的非法token添加到黑名单中,每次验证token是否有效要先过黑名单,如果存在黑名单中直接拒绝。
  • 5.由于json的通用性,所以JWT是可以进行跨语言支持的。

总结

通过本文,我们对JWT是什么有了一个全面的了解,以及它是如何在认证中被使用的。JWT只是一个简单的JSON对象,并且易于验证、难于伪造。

此外,JWT并不是一定要用来做认证的,我们可以使用JWT在网络上发送各种数据。

另外一个和安全相关的使用JWT的情况是授权:我们可以在Payload里面放置用户的角色列表,比如只读用户、管理员等等,对用户在应用服务器上的行为进行限制。

参考

[1]什么是 JWT?

[2]Base64字符串解码和编码

[3]非对称加密详解

[4]Token和Jwt的区别


文章作者: Alex
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 Alex !
  目录