JWT实现分布式Session

2019/07/06

一、JWT官方定义

我在学习任何一门技术前都会先去看它的官方定义,这是从学生时代养成的习惯<~^~>

What is JSON Web Token?

JSON Web Token (JWT) is an open standard (RFC 7519) that defines a compact and self-contained way for securely transmitting information between parties as a JSON object. This information can be verified and trusted because it is digitally signed. JWTs can be signed using a secret (with the HMAC algorithm) or a public/private key pair using RSA or ECDSA.

二、JWT到底是什么

为什么要学习jwt呢,是Session不好用吗? 额…….当然是工作项目的需要喽。

JWT全称为JSON Web Token,从三个单词就可以看出

1、数据是JSON格式 2、用于Web应用 3、是一个Token、也就是一个令牌

官方定义大概就是:JWT定义了一种紧凑且自包含的方式,用于在各方之间以JSON对象进行安全传输信息。这些信息可以通过对称/非对称方式进行签名,防止信息被串改。

  • 紧凑的含义: 就是JWT比较小,数据量不大,所以可以通过URL、POST、参数或Header请求方式进行传输。

  • 自包含的含义:jwt可以让用户自定义JWT里面包含的用户信息,如:用户id、姓名等(不要放隐密的信息)。从而避免了多次查询数据库。

三、JWT数据结构

  • 一个JWT实际上就是一个字符串,它由三部分组成.

1、头部(Heaher)

2、载荷(Payload)

3、签名(Signature)

  • 三者组合在一起

Header.Payload.Signature

  • 案例
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJsaW5neGUtY2xvdWQiLCJleHAiOjE1NjA5NTMyMzEsInVzZXJJZCI6IjkxYjJmNjk4ZjI1YzRiNTNiMjJlNmY2ODM2N2QzZjJmIn0.Nr9eANxj3RRER3elaxyrURN9WLbWMg6HVHI_F-gQsPc

四、头部(Header)

头部用于描述关于该JWT的最基本的信息,例如其类型以及签名所用的算法等。

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

1、typ属性表示这个令牌的类型,JWT令牌就为JWT。

2、alg属性表示签名的算法,默认算法为HS256,可以自行别的算法。

上面的JSON数据会通过Base64算法进行编码而成,看工具图

五、载荷(Payload)

此为JWT第二段数据,用来存放实际需要传递的数据。JWT官方也规定了7个字段供选用

  • iss (issuer): 签发人

  • exp (expiration time): 过期时间

  • sub (subject): 主题

  • aud (audience): 受众

  • nbf (Not Before): 生效时间

  • iat (Issued At): 签发时间

  • jti (JWT ID): 编号

除了官方字段,我们可以自定义字段,例如自定义一些用户相关字段。

注意: 这段也是用Base64算法,JWT默认是不加密的,任何人都可以获取,只要进行Base64解码就行了,所以不要把隐密的信息放到JWT中

六、签名(Signature)

此为JWT第三段数据,主要作用是对前面两段的数据进行签名,防止数据篡改。一般我们进行签名的时候会有个密钥(secret),只有服务器知道,然后利用Header中的签名算法进行签名,公式如下:

HMACSHA256( base64Encode(header) + “.” + base64Encode(payload), secret)

算出签名后,把Header、Payload、Signature三个部分拼成一个字符串,之间用(.)分隔,这样就可以把组合而成的字符串返回给用户了。

签名的目的

最后一步签名的过程,实际上是对头部以及载荷内容进行签名。一般而言,加密算法对于不同的输入产生的输出总是不一样的。对于两个不同的输入,产生同样的输出的概率极其地小。所以,我们就把“不一样的输入产生不一样的输出”当做必然事件来看待吧。

所以,如果有人对头部以及载荷的内容解码之后进行修改,再进行编码的话,那么新的头部和载荷的签名和之前的签名就将是不一样的。而且,如果不知道服务器加密的时候用的密钥的话,得出来的签名也一定会是不一样的。

服务器应用在接受到JWT后,会首先对头部和载荷的内容用同一算法再次签名。那么服务器应用是怎么知道我们用的是哪一种算法呢?别忘了,我们在JWT的头部中已经用alg字段指明了我们的加密算法了。

如果服务器应用对头部和载荷再次以同样方法签名之后发现,自己计算出来的签名和接受到的签名不一样,那么就说明这个Token的内容被别人动过的,我们应该拒绝这个Token,返回一个HTTP 401 Unauthorized响应。

七、JWT的工作方式

在用户进行认证登录时,登录成功后服务器会返回一个JWT给客户端;那这个JWT就是用户的凭证,以后到哪里去都要带上这个凭证token。尤其访问受保护的资源的时候,通常把JWT放在Authorization header中。

八、基于JWT的身份认证

上面的JWT的工作方式,其实就是一个完整的身份认证流程,大概描述就是:

1、用户提供用户名和密码登录

2、服务器校验用户是否正确,如正确,就返回token给客户端,此token可以包含用户信息

3、客户端存储token,可以保存在cookie或者local storage

4、客户端以后请求时,都要带上这个token,一般放在请求头中

5、服务器判断是否存在token,并且解码后就可以知道是哪个用户

6、服务器这样就可以返回该用户的相关信息了

基于JWT的身份认证方式和Session的认证方式最大的不同在于用户信息存放在JWT中的,是存放在客户端的。而Session是将用户信息存放在了服务端。

九、与Session-Cookie方式的区别

传统的Session-Cookie的方式在这里就不赘述了,直接上图说明区别

上图是Sesson服务器方式,我们发现Session用户信息是在服务器端存储的。

再来看看JWT方式

上面的token即用户信息是存储在客户端的,服务器端只要解码即可。

十、JWT方式认证的好处

1、因为token存储在客户端,服务器只负责解码。这样不需要占用服务器端资源。

2、服务器端可以无限扩展,负载均衡器可以将用户传递到任何服务器,服务器都能知道用户信息,因为jwt里面包含了。

3、数据安全,因为有签名,防止了篡改,但信息还是透明的,不要放敏感信息。

4、放入请求头提交,很好的防止了csrf攻击

十一、JWT方式的坏处

1、token失效问题

JWT方式最大的坏处就是无法主动让token失效,小伙伴们会说token不是有过期时间吗?是的,token本身是有过期时间,但token一旦发出,服务器就无法收回。

如:一个jwt的token的失效时间是3天,但我们发现这个token有异常,有可能被人登录,那真实的用户可以修改密码。但是即使修改了密码,那个异常的token还是合法的,因为3天的失效时间未到,我们服务器是没法主动让异常token失效。

2、数据延时,不一致

还有个问题就是因为jwt中包含了用户的部分信息,如果这些部分信息修改了,服务器获取的还是以前的jwt中的用户信息,导致数据不一致。

3、续签问题

续签问题可以说是我抵制使用 jwt 来代替传统 session 的最大原因,因为 jwt 的设计中我就没有发现它将续签认为是自身的一个特性。传统的 cookie 续签方案一般都是框架自带的,session 有效期 30 分钟,30 分钟内如果有访问,session 有效期被刷新至 30 分钟。而 jwt 本身的 payload 之中也有一个 exp 过期时间参数,来代表一个 jwt 的时效性,而 jwt 想延期这个 exp 就有点身不由己了,因为 payload 是参与签名的,一旦过期时间被修改,整个 jwt 串就变了,jwt 的特性天然不支持续签!(我们可以使用一些特殊的手段去解决这个问题)

十二、JWT的使用场景

1、一次性验证

比如用户注册后需要发一封邮件让其激活账户,通常邮件中需要有一个链接,这个链接需要具备以下的特性:能够标识用户,该链接具有时效性(通常只允许几小时之内激活),不能被篡改以激活其他可能的账户…这种场景就和 jwt 的特性非常贴近,jwt 的 payload 中固定的参数:iss 签发者和 exp 过期时间正是为其做准备的。

2、restful api的无状态认证

使用 jwt 来做 restful api 的身份认证也是值得推崇的一种使用方案。客户端和服务端共享 secret;过期时间由服务端校验,客户端定时刷新;签名信息不可被修改…spring security oauth jwt 提供了一套完整的 jwt 认证体系。

3.使用 jwt 做单点登录+会话管理(不推荐)


扫码加好友

(转载本站文章请注明作者和出处 major-http://www.major818.com

Show Disqus Comments

Post Directory