用户认证:基于jwt和session的区别和优缺点

背景知识:

Authentication和Authorization的区别:
redis

  • Authentication:用户认证,指的是验证用户的身份,例如你但愿以小A的身份登陆,那么应用程序须要经过用户名和密码确认你真的是小A。算法

  • Authorization:受权,指的是确认你的身份以后提供给你权限,例如用户小A能够修改数据,而用户小B只能阅读数据。数据库


因为http协议是无状态的,每一次请求都无状态。当一个用户经过用户名和密码登陆了以后,他的下一个请求不会携带任何状态,应用程序没法知道他的身份,那就必须从新认证。所以咱们但愿用户登陆成功以后的每一次http请求,都可以保存他的登陆状态。
json

目前主流的用户认证方法有基于token和基于session两种方式。
后端

基于session的用户认证
浏览器

基于session的认证流程以下:安全

图片

  1. 用户输入其登陆信息服务器

  2. 服务器验证信息是否正确,并建立一个session,而后将其存储在数据库中cookie

  3. 服务器为用户生成一个sessionId,将具备sesssionId的Cookie将放置在用户浏览器中session

  4. 在后续请求中,会根据数据库验证sessionID,若是有效,则接受请求

  5. 一旦用户注销应用程序,会话将在客户端和服务器端都被销毁

基于token(令牌)的用户认证

最经常使用的是JSON Web Token(jwt):

图片

  1. 用户输入其登陆信息

  2. 服务器验证信息是否正确,并返回已签名的token

  3. token储在客户端,例如存在local storage或cookie中

  4. 以后的HTTP请求都将token添加到请求头里

  5. 服务器解码JWT,而且若是令牌有效,则接受请求

  6. 一旦用户注销,令牌将在客户端被销毁,不须要与服务器进行交互一个关键是,令牌是无状态的。后端服务器不须要保存令牌或当前session的记录。

jwt的组成

jwt的认证原理:

一个jwt实际上就是一个字符串,它由三部分组成,头部、载荷与签名,这三个部分都是json格式。

头部(Header)

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

{  "typ": "JWT",  "alg": "HS256"}
在这里,咱们说明了这是一个JWT,而且咱们所用的签名算法是HS256算法。

载荷(Payload)

载荷能够用来放一些不敏感的信息。


{    "iss": "John Wu JWT",    "iat": 1441593502,    "exp": 1441594722,    "aud": "www.example.com",    "sub": "jrocket@example.com",    "from_user": "B",    "target_user": "A"}
这里面的前五个字段都是由JWT的标准所定义的。
  • iss: 该JWT的签发者

  • sub: 该JWT所面向的用户

  • aud: 接收该JWT的一方

  • exp(expires): 何时过时,这里是一个Unix时间戳

  • iat(issued at): 在何时签发的 把头部和载荷分别进行Base64编码以后获得两个字符串,而后再将这两个编码后的字符串用英文句号.链接在一块儿(头部在前),造成新的字符串:

eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJmcm9tX3VzZXIiOiJCIiwidGFyZ2V0X3VzZXIiOiJBIn0

签名(signature)

最后,咱们将上面拼接完的字符串用HS256算法进行加密。在加密的时候,咱们还须要提供一个密钥(secret)。加密后的内容也是一个字符串,最后这个字符串就是签名,把这个签名拼接在刚才的字符串后面就能获得完整的jwt。header部分和payload部分若是被篡改,因为篡改者不知道密钥是什么,也没法生成新的signature部分,服务端也就没法经过,在jwt中,消息体是透明的,使用签名能够保证消息不被篡改。

eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJmcm9tX3VzZXIiOiJCIiwidGFyZ2V0X3VzZXIiOiJBIn0.rSWamyAYwuHCo7IFAgd1oRpSP7nzL7BF5t7ItqpKViM

区别和优缺点:

基于session和基于jwt的方式的主要区别就是用户的状态保存的位置,session是保存在服务端的,而jwt是保存在客户端的。

jwt的优势:

  • 可扩展性好 应用程序分布式部署的状况下,session须要作多机数据共享,一般能够存在数据库或者redis里面。而jwt不须要。

  • 无状态 jwt不在服务端存储任何状态。RESTful API的原则之一是无状态,发出请求时,总会返回带有参数的响应,不会产生附加影响。用户的认证状态引入这种附加影响,这破坏了这一原则。另外jwt的载荷中能够存储一些经常使用信息,用于交换信息,有效地使用 JWT,能够下降服务器查询数据库的次数。

jwt的缺点:

安全性

因为jwt的payload是使用base64编码的,并无加密,所以jwt中不能存储敏感数据。而session的信息是存在服务端的,相对来讲更安全。


性能

jwt太长。因为是无状态使用JWT,全部的数据都被放到JWT里,若是还要进行一些数据交换,那载荷会更大,通过编码以后致使jwt很是长,cookie的限制大小通常是4k,cookie极可能放不下,因此jwt通常放在local storage里面。而且用户在系统中的每一次http请求都会把jwt携带在Header里面,http请求的Header可能比Body还要大。而sessionId只是很短的一个字符串,所以使用jwt的http请求比使用session的开销大得多。


一次性

无状态是jwt的特色,但也致使了这个问题,jwt是一次性的。想修改里面的内容,就必须签发一个新的jwt。

(1)没法废弃 经过上面jwt的验证机制能够看出来,一旦签发一个jwt,在到期以前就会始终有效,没法中途废弃。例如你在payload中存储了一些信息,当信息须要更新时,则从新签发一个jwt,可是因为旧的jwt还没过时,拿着这个旧的jwt依旧能够登陆,那登陆后服务端从jwt中拿到的信息就是过期的。为了解决这个问题,咱们就须要在服务端部署额外的逻辑,例如设置一个黑名单,一旦签发了新的jwt,那么旧的就加入黑名单(好比存到redis里面),避免被再次使用。

(2)续签 若是你使用jwt作会话管理,传统的cookie续签方案通常都是框架自带的,session有效期30分钟,30分钟内若是有访问,有效期被刷新至30分钟。同样的道理,要改变jwt的有效时间,就要签发新的jwt。最简单的一种方式是每次请求刷新jwt,即每一个http请求都返回一个新的jwt。这个方法不只暴力不优雅,并且每次请求都要作jwt的加密解密,会带来性能问题。另外一种方法是在redis中单独为每一个jwt设置过时时间,每次访问时刷新jwt的过时时间。

能够看出想要破解jwt一次性的特性,就须要在服务端存储jwt的状态。可是引入 redis 以后,就把无状态的jwt硬生生变成了有状态了,违背了jwt的初衷。并且这个方案和session都差很少了。

总结

适合使用jwt的场景:

  • 有效期短

  • 只但愿被使用一次

好比,用户注册后发一封邮件让其激活帐户,一般邮件中须要有一个连接,这个连接须要具有如下的特性:可以标识用户,该连接具备时效性(一般只容许几小时以内激活),不能被篡改以激活其余可能的帐户,一次性的。这种场景就适合使用jwt。

而因为jwt具备一次性的特性。单点登陆和会话管理很是不适合用jwt,若是在服务端部署额外的逻辑存储jwt的状态,那还不如使用session。基于session有不少成熟的框架能够开箱即用,可是用jwt还要本身实现逻辑。

相关文章
相关标签/搜索