以后我的项目JWT登录鉴权办法及问题

以后登陆鉴权办法

用户登录时,返回一个JWT,由前端存储在本地。尔后用户每次向须要权限的API发出请求时带上该JWT用于验证身份。
后端收到JWT后,验证JWT是否正确且未过期:

  1. 如果正确且未过期,则返回资源。
  2. 如果不正确,则返回不正确的状态码;如果已过期,则返回已过期的状态码,要求从新登录。

问题

应用JWT实现登录鉴权时,因为JWT有固定的过期工夫,可能在用户正在进行操作的过程中恰好过期,而后忽然跳转到登录界面,造成较差的用户体验。

指标

应用JWT实现登录鉴权,当且仅当用户在一段时间内不对系统进行任何操作时才要求用户从新登录,并且尽可能保障JWT的安全性。

解决办法及优缺点剖析

解决办法一:只应用一个JWT token(不举荐)

具体实现

用户登录时,返回一个JWT,由前端存储在本地。尔后用户每次向须要权限的API发出请求时带上该JWT用于验证身份。
后端收到JWT后,验证该JWT是否正确:

  1. 如果不正确,则间接返回错误代码;
  2. 如果正确,则验证该JWT是否过期:

    • 如果没有过期,则间接返回资源;
    • 如果过期,则计算过期工夫:

      • 如果过期工夫没有超过某阈值,则返回资源和新的JWT;
      • 如果过期工夫超过某阈值,则返回错误代码。要求从新登录。
长处

实现了当且仅当用户在一段时间内不对系统进行任何操作时才要求用户从新登录。
当JWT过期时如果用户还在操作系统,会向后端发送刚刚过期的JWT,此时JWT的过期工夫没有超过阈值,间接返回资源和新的JWT,实现用户无感书最新。
然而如果当JWT过期之后的一段时间(阈值内)用户都没有操作系统,当用户再次操作系统时,会向后端发送过期工夫超过阈值的JWT,后端会返回错误代码,实现从新登录。

毛病

安全性较低。如果频繁发送申请,能够应用一个JWT实现永恒登录。一旦JWT被窃取,攻击者能够应用失去的JWT永恒伪造用户获取信息。

解决方案二:应用两个JWT token(举荐)

具体实现

用户登录时,返回两个JWT(access token和refresh token),一个用于在申请资源验证身份的access token,一个用于在access token过期时更新access token的refresh token。其中refresh token的有效期较长(如7天),而access token的有效期较短(如1小时)。由前端存储在本地。尔后用户每次向须要权限的API发出请求时带上access token用于验证身份。
后端收到access token后:验证该access token是否正确:

  1. 如果不正确,则间接返回错误代码;
  2. 如果正确,则验证该access token是否过期:

    • 如果没过期,则间接返回资源;
    • 如果过期,则返回过期的错误代码。前端收到过期错误代码后应用refresh token向更新接口申请新的access token,更新接口判断refresh token是否过期:

      • 如果没有过期,则返回新的access token和新的refresh token,将之前所有由同一refresh token生成的refresh token都置为有效(保护一个有效列表)。前端应用新的access token从新向须要权限的API发出请求,获取资源。
      • 如果过期,则返回错误代码,要求从新登录。
      • 如果收到已被置为有效的refresh token,则将以后所有与有效refresh token为同一用户的refresh token和access token都置为有效(具体来说是将该用户的拜访置为有效),直到用户从新登录。

应用这种办法,既能防止在用户操作的过程中呈现忽然跳转登录(次要解决了两次操作之间的不统一景象,不会呈现一次申请还能失常获取资源,下一次申请资源就忽然跳转到登录页面的景象),又能保障较高的安全性。

解释
Q:为什么不应用永恒无效的refresh token?

A:为了实现更高的安全性。永恒无效的refresh token一旦被窃取,攻击者能够应用该token永恒假冒用户获取个人信息。而每次应用refresh token就更换一个新的refresh token的话,即便refresh token被窃取,也会在肯定工夫内生效,攻击者应用的工夫无限。

Q:为什么refresh token获取新的access token时须要同时更新refresh token?

A:因为如果不更新refresh token的话,就无奈防止用户两次操作之间的不一致性。可能用户在refresh token过期前一分钟还能失常操作,一分钟后就忽然跳转到登录页面,造成不敌对的用户体验。

Q:为什么要在应用refresh token取得新的access token和refresh token后将用于申请新token的refresh token置为有效?

A:为了防止之前的refresh token被窃取后导致的重放攻打(应用之前的refresh token申请新的access token和refresh token)。

Q:为什么更新接口在收到已置为有效的refresh token后会将所有应用第一个refresh token失去的refresh token都禁止?

A:因为不晓得被窃取的是哪个refresh token。有可能攻击者应用第一个refresh token,并应用该token在更新接口获取了新的refresh token,此时用户可能应用旧的refresh token(已被置为有效)申请更新接口。也有可能攻击者窃取到第一个refresh token后,用户首先应用该token在更新接口获取了新的refresh token,此时攻击者可能应用旧的refresh token(已置为有效)申请更新接口。详见:auth0-refresh-token-rotation

Q:如何在禁止一个refresh token时将对应的access token置为有效?

A:

  1. 缩短JWT的无效工夫,而后禁止refresh token:然而access token最短也有一个固定的有效期限(5~10min),可能给攻击者提供5~10min应用该token的工夫。
  2. 保护一个blacklist:当一个refresh token被禁止时将该音讯播送到所有无关的服务器,所有的服务器保护一个refresh token被禁止的用户列表,每次接到一个access token时,判断其对应的refresh token是否被禁止,如果是就间接返回谬误状态码。
  3. 详见:fusionauth-revoking-jwts

JWT VS Session:登录鉴权如何选

二者都是为了在无状态的HTTP协定中记录登录状态,以防止每次申请都要验证身份。

Session实现登录鉴权

用户登录胜利后,服务器生成一个对应的session ID,存储在(内存里的)文件或数据库中,并且放在cookie中返回给浏览器。登录后每次申请会发送cookie,在服务端的存储中查找cookie中的session ID以验证用户身份。

比照

  1. (程度)扩展性:当用户量增大时,须要应用多台服务器解决拜访。

    • 如果应用session,须要解决服务器端存储session ID的问题,因而须要一个集中的session存储器,个别是一台专门用于运行redis的服务器。然而这样也会面临访问量瓶颈的问题。并且同时在线人数过多时须要存储大量session ID,从而占用大量服务器资源。
    • 如果应用JWT,就不必在服务端存储每个用户的登录信息(除了还未过期但被禁用的refresh token,然而不必在用户申请业务接口时验证,只用在更新token时验证,不会影响业务接口的响应工夫)。任何一台服务器都能间接通过JWT判断是否是非法的登录用户。
  2. 性能:如果JWT中蕴含了很多数据,则它会远大于一个session ID,会给HTTP申请带来额定的开销。然而session每次都要查找一次数据库来验证用户身份。
  3. 在服务端破除session/token(如用户批改明码后破除原来的session/token):

    • 如果应用session:比较简单,间接从数据库中删除session ID即可。
    • 如果应用JWT:比较复杂。因为token一旦签发,在有效期内都能被服务器认证。须要保护一个被禁用的access token的blacklist,申请业务接口时查找。
  4. 在服务端禁止用户:

    • 如果应用session:比较简单,间接从数据库中删除session ID即可。
    • 如果应用JWT:比较复杂。因为token一旦签发,在有效期内都能被服务器认证。禁止用户须要禁用用户所有还在有效期内的access token和refresh token。须要保护一个被禁用用户的blacklist,申请业务接口/更新access token都要查找。

参考

  • 基于JWT+Refresh Token的用户认证实际
  • auth0 refresh token
  • auth0 refresh token rotation
  • 是抉择长时间的 access token 还是短时间的 access token+刷新
  • 破除有效 JWT
  • JWT 与 Session
  • JWT禁用问题