我希望对新的REST API实现基于jwt的身份验证。但是由于到期时间是在令牌中设置的,那么是否可以自动延长它呢?我不希望用户每隔X分钟就需要登录一次,如果他们在这段时间内积极使用应用程序的话。这将是一个巨大的用户体验失败。

但是延长过期时间会创建一个新的令牌(旧的令牌在过期前仍然有效)。在每个请求后生成一个新的令牌对我来说听起来很傻。当多个令牌同时有效时,听起来像是一个安全问题。当然,我可以使用黑名单使旧的使用无效,但我需要存储令牌。JWT的好处之一是没有存储空间。

我发现Auth0是如何解决这个问题的。他们不仅使用JWT令牌,还使用refresh令牌: https://auth0.com/docs/tokens/refresh-tokens

但是,要实现这一点(没有Auth0),我需要存储刷新令牌并维护它们的过期。那么真正的好处是什么呢?为什么不只有一个令牌(不是JWT)并将过期时间保存在服务器上呢?

还有其他选择吗?使用JWT不适合这种情况吗?


当前回答

问得好——问题本身包含了丰富的信息。

文章“刷新令牌:何时使用它们以及它们如何与jwt交互”为这种场景提供了一个很好的想法。一些要点是:-

刷新令牌携带获取新访问所需的信息 令牌。 刷新令牌也会过期,但寿命相当长。 刷新令牌通常需要严格的存储要求 确保它们不会泄露。 它们还可以被授权服务器列入黑名单。

也可以看看auth0/angular-jwt angularjs

用于Web API。在AngularJS应用程序中启用OAuth刷新令牌使用ASP .NET Web API 2和Owin

其他回答

这个方法怎么样:

对于每个客户端请求,服务器将令牌的过期时间与(currentTime - lastAccessTime)进行比较。 如果expirationTime < (currentTime - lastAccessedTime),则将上一次lastAccessedTime更改为currentTime。 如果浏览器上的不活动时间超过了过期时间,或者如果浏览器窗口被关闭并且过期时间为> (currentTime - lastAccessedTime),那么服务器可以使令牌过期并要求用户再次登录。

在这种情况下,刷新令牌不需要额外的端点。 将感激任何反馈。

当我在后端将我们的应用程序移动到带有RESTful api的HTML5时,我正在进行修补。我想到的解决办法是:

成功登录后,客户端将获得一个会话时间为30分钟(或通常的服务器端会话时间)的令牌。 创建一个客户端计时器来调用服务,以便在令牌到期之前更新令牌。新的令牌将在未来的调用中取代现有的令牌。

如您所见,这减少了频繁的刷新令牌请求。如果用户在更新令牌调用触发之前关闭浏览器/应用程序,之前的令牌将及时过期,用户将不得不重新登录。

可以采用更复杂的策略来应对用户不活跃(例如忽略打开的浏览器选项卡)。在这种情况下,更新令牌调用应该包括预期的到期时间,该时间不应该超过所定义的会话时间。应用程序必须相应地跟踪最后一次用户交互。

我不喜欢设置较长的过期时间,因此这种方法可能不适用于需要较少频繁身份验证的本机应用程序。

我通过在令牌数据中添加一个变量来解决这个问题:

softexp - I set this to 5 mins (300 seconds)

我将expiresIn选项设置为我想要的时间,然后用户将被迫再次登录。我的设定是30分钟。这必须大于softexp的值。

当我的客户端应用程序发送请求到服务器API(令牌是必需的,例如。客户列表页面),服务器根据其原始到期值(expiresIn)检查所提交的令牌是否仍然有效。如果它是无效的,服务器将响应此错误的状态,例如。INVALID_TOKEN。

如果基于expiredIn值令牌仍然有效,但它已经超过了softexp值,服务器将对此错误响应一个单独的状态,例如。EXPIRED_TOKEN:

(Math.floor(Date.now() / 1000) > decoded.softexp)

在客户端,如果它收到EXPIRED_TOKEN响应,它应该通过向服务器发送更新请求来自动更新令牌。这对用户是透明的,并自动被客户端应用程序照顾。

服务器中的更新方法必须检查令牌是否仍然有效:

jwt.verify(token, secret, (err, decoded) => {})

如果上述方法失败,服务器将拒绝更新令牌。

JWT的想法很好,你把你需要的东西放进JWT,然后无状态化。 两个问题:

糟糕的JWT标准化。 JWT是不可能失效的,如果创建快速到期,它会迫使用户频繁登录。

1的解。使用自定义JSON:

 {"userId": "12345", "role": "regular_user"}

使用对称(AES)算法加密它(它比使用非对称算法签名更快),并将其放入快速过期的cookie中。我仍然会称它为JWT,因为它是JSON,并且在Web应用程序中用作令牌。现在,服务器检查cookie是否存在,其值是否可以解密。

2的解。使用刷新令牌:

将userId作为12345,对其加密,并将其放入长期过期的cookie中。不需要在DB中为刷新令牌创建一个特殊字段。

现在,每次访问令牌(JWT) cookie过期时,服务器都会检查刷新令牌cookie,解密,获取值,并在DB中查找用户。如果找到用户,则生成一个新的访问令牌,否则(或者如果刷新令牌也过期)强制用户登录。

最简单的替代方法是使用刷新令牌作为访问令牌,即根本不使用JWT。

使用JWT的优点是,在它的过期时间内,服务器不会访问DB。即使我们在cookie中放入一个过期时间只有2分钟的访问令牌,对于像eBay这样繁忙的应用程序,它也会导致每秒避免数千DB的点击。

以下是撤销JWT访问令牌的步骤:

1) When you do login, send 2 tokens (Access token, Refresh token) in response to client . 2) Access token will have less expiry time and Refresh will have long expiry time . 3) Client (Front end) will store refresh token in his local storage and access token in cookies. 4) Client will use access token for calling apis. But when it expires, pick the refresh token from local storage and call auth server api to get the new token. 5) Your auth server will have an api exposed which will accept refresh token and checks for its validity and return a new access token. 6) Once refresh token is expired, User will be logged out.

如果你需要更多细节,请告诉我,我也可以分享代码(Java + Spring引导)。