JWT(JSON Web Token)自动延长到期时间
本文翻译自:JWT (JSON Web Token) automatic prolongation of expiration
I would like to implement JWT-based authentication to our new REST API. 我想对我们的新REST API实现基于JWT的身份验证。 But since the expiration is set in the token, is it possible to automatically prolong it? 但是由于在令牌中设置了到期,是否可以自动延长它? I don't want users to need to sign in after every X minutes if they were actively using the application in that period. 如果他们在那段时间内积极使用该应用程序,我不希望用户在每X分钟后需要登录。 That would be a huge UX fail. 这将是一个巨大的用户体验失败。
But prolonging the expiration creates a new token (and the old one is still valid until it expires). 但是延长过期会创建一个新令牌(旧令牌在到期之前仍然有效)。 And generating a new token after each request sounds silly to me. 每次请求后生成一个新令牌听起来很傻。 Sounds like a security issue when more than one token is valid at the same time. 当多个令牌同时有效时,听起来像是一个安全问题。 Of course I could invalidate the old used one using a blacklist but I would need to store the tokens. 当然,我可以使用黑名单使旧的旧的无效,但我需要存储令牌。 And one of the benefits of JWT is no storage. JWT的一个好处就是没有存储空间。
I found how Auth0 solved it. 我发现Auth0是如何解决它的。 They use not only JWT token but also a refresh token: https://docs.auth0.com/refresh-token 它们不仅使用JWT令牌,还使用刷新令牌: https : //docs.auth0.com/refresh-token
But again, to implement this (without Auth0) I'd need to store refresh tokens and maintain their expiration. 但同样,要实现这一点(没有Auth0),我需要存储刷新令牌并保持其过期。 What is the real benefit then? 那么真正的好处是什么? Why not have only one token (not JWT) and keep the expiration on the server? 为什么不只有一个令牌(不是JWT)并在服务器上保持过期?
Are there other options? 还有其他选择吗? Is using JWT not suited for this scenario? 使用JWT不适合这种情况吗?
#1楼
参考:https://stackoom.com/question/1oC4t/JWT-JSON-Web-Token-自动延长到期时间
#2楼
I work at Auth0 and I was involved in the design of the refresh token feature. 我在Auth0工作,我参与了刷新令牌功能的设计。
It all depends on the type of application and here is our recommended approach. 这一切都取决于应用程序的类型,这是我们推荐的方法。
Web applications Web应用程序
A good pattern is to refresh the token before it expires. 一个好的模式是在令牌过期之前刷新令牌。
Set the token expiration to one week and refresh the token every time the user open the web application and every one hour. 将令牌过期设置为一周,并在每次用户打开Web应用程序时每隔一小时刷新令牌。 If a user doesn't open the application for more than a week, they will have to login again and this is acceptable web application UX. 如果用户未打开应用程序超过一周,则必须再次登录,这是可接受的Web应用程序UX。
To refresh the token your API needs a new endpoint that receives a valid, not expired JWT and returns the same signed JWT with the new expiration field. 要刷新令牌,您的API需要一个新端点,该端点接收有效的,未过期的JWT,并返回带有新过期字段的相同签名JWT。 Then the web application will store the token somewhere. 然后,Web应用程序将令牌存储在某处。
Mobile/Native applications 移动/本机应用程序
Most native applications do login once and only once. 大多数本机应用程序只登录一次。
The idea is that the refresh token never expires and it can be exchanged always for a valid JWT. 我们的想法是刷新令牌永不过期,并且可以始终为有效的JWT进行交换。
The problem with a token that never expires is that never means never. 永不过期的令牌问题绝不是永远不会。 What do you do if you lose your phone? 如果丢失手机怎么办? So, it needs to be identifiable by the user somehow and the application needs to provide a way to revoke access. 因此,它需要以某种方式由用户识别,并且应用程序需要提供撤销访问的方法。 We decided to use the device's name, eg "maryo's iPad". 我们决定使用该设备的名称,例如“maryo的iPad”。 Then the user can go to the application and revoke access to "maryo's iPad". 然后,用户可以转到该应用程序并撤消对“maryo的iPad”的访问权限。
Another approach is to revoke the refresh token on specific events. 另一种方法是撤消特定事件上的刷新令牌。 An interesting event is changing the password. 一个有趣的事件是更改密码。
We believe that JWT is not useful for these use cases so we use a random generated string and we store it on our side. 我们认为JWT对这些用例没用,所以我们使用随机生成的字符串,然后将它存储在我们这边。
#3楼
In the case where you handle the auth yourself (ie don't use a provider like Auth0), the following may work: 在您自己处理auth的情况下(即不使用Auth0之类的提供程序),以下内容可能有效:
- Issue JWT token with relatively short expiry, say 15min. 发出JWT令牌,到期时间相对较短,比如15分钟。
- Application checks token expiry date before any transaction requiring a token (token contains expiry date). 应用程序在任何需要令牌的交易(令牌包含到期日期)之前检查令牌到期日期。 If token has expired, then it first asks API to 'refresh' the token (this is done transparently to the UX). 如果令牌已过期,则它首先要求API“刷新”令牌(这对UX是透明的)。
- API gets token refresh request, but first checks user database to see if a 'reauth' flag has been set against that user profile (token can contain user id). API获取令牌刷新请求,但首先检查用户数据库以查看是否已针对该用户配置文件设置了“reauth”标志(令牌可以包含用户ID)。 If the flag is present, then the token refresh is denied, otherwise a new token is issued. 如果该标志存在,则拒绝令牌刷新,否则发出新令牌。
- Repeat. 重复。
The 'reauth' flag in the database backend would be set when, for example, the user has reset their password. 例如,当用户重置密码时,将设置数据库后端中的“reauth”标志。 The flag gets removed when the user logs in next time. 用户下次登录时会删除该标志。
In addition, let's say you have a policy whereby a user must login at least once every 72hrs. 此外,假设您有一项政策,用户必须至少每72小时登录一次。 In that case, your API token refresh logic would also check the user's last login date from the user database and deny/allow the token refresh on that basis. 在这种情况下,您的API令牌刷新逻辑还将检查用户从用户数据库的上次登录日期,并在此基础上拒绝/允许令牌刷新。
#4楼
I was tinkering around when moving our applications to HTML5 with RESTful apis in the backend. 在后端使用RESTful apis将应用程序移动到HTML5时,我正在修补。 The solution that I came up with was: 我想出的解决方案是:
- Client is issued with a token with a session time of 30 mins (or whatever the usual server side session time) upon successful login. 成功登录后,将向客户端发出一个会话时间为30分钟(或通常的服务器端会话时间)的令牌。
- A client-side timer is created to call a service to renew the token before its expiring time. 创建客户端计时器以调用服务以在令牌到期之前续订令牌。 The new token will replace the existing in future calls. 新令牌将替换将来调用中的现有令牌。
As you can see, this reduces the frequent refresh token requests. 如您所见,这减少了频繁的刷新令牌请求。 If user closes the browser/app before the renew token call is triggered, the previous token will expire in time and user will have to re-login. 如果用户在触发续订令牌呼叫之前关闭浏览器/应用程序,则先前令牌将及时到期,用户必须重新登录。
A more complicated strategy can be implemented to cater for user inactivity (eg neglected an opened browser tab). 可以实现更复杂的策略以满足用户不活动(例如,忽略打开的浏览器选项卡)。 In that case, the renew token call should include the expected expiring time which should not exceed the defined session time. 在这种情况下,续订令牌调用应包括预期的到期时间,该时间不应超过定义的会话时间。 The application will have to keep track of the last user interaction accordingly. 应用程序必须相应地跟踪最后的用户交互。
I don't like the idea of setting long expiration hence this approach may not work well with native applications requiring less frequent authentication. 我不喜欢设置长期到期的想法,因此这种方法可能不适用于需要较少频繁身份验证的本机应用程序。
#5楼
How about this approach: 这种方法怎么样:
- For every client request, the server compares the expirationTime of the token with (currentTime - lastAccessTime) 对于每个客户端请求,服务器将令牌的expirationTime与(currentTime - lastAccessTime)进行比较
- If expirationTime < (currentTime - lastAccessedTime) , it changes the last lastAccessedTime to currentTime. 如果expirationTime <(currentTime - lastAccessedTime) ,则将最后lastEccessedTime更改为currentTime。
- In case of inactivity on the browser for a time duration exceeding expirationTime or in case the browser window was closed and the expirationTime > (currentTime - lastAccessedTime) , and then the server can expire the token and ask the user to login again. 如果浏览器长时间不活动超过expirationTime,或者浏览器窗口关闭且expirationTime>(currentTime - lastAccessedTime) ,则服务器可以使令牌过期并要求用户再次登录。
We don't require additional end point for refreshing the token in this case. 在这种情况下,我们不需要额外的终点来刷新令牌。 Would appreciate any feedack. 非常感谢任何feedack。
#6楼
jwt-autorefresh 智威汤逊-自动刷新
If you are using node (React / Redux / Universal JS) you can install npm i -S jwt-autorefresh
. 如果您正在使用节点(React / Redux / Universal JS),则可以安装npm i -S jwt-autorefresh
。
This library schedules refresh of JWT tokens at a user calculated number of seconds prior to the access token expiring (based on the exp claim encoded in the token). 此库根据用户计算的访问令牌到期之前的秒数(基于令牌中编码的exp声明)计划刷新JWT令牌。 It has an extensive test suite and checks for quite a few conditions to ensure any strange activity is accompanied by a descriptive message regarding misconfigurations from your environment. 它有一个广泛的测试套件,可以检查很多条件,以确保任何奇怪的活动都伴随着有关环境配置错误的描述性消息。
Full example implementation 完整的示例实现
import autorefresh from 'jwt-autorefresh'
/** Events in your app that are triggered when your user becomes authorized or deauthorized. */
import { onAuthorize, onDeauthorize } from './events'
/** Your refresh token mechanism, returning a promise that resolves to the new access tokenFunction (library does not care about your method of persisting tokens) */
const refresh = () => {
const init = { method: 'POST'
, headers: { 'Content-Type': `application/x-www-form-urlencoded` }
, body: `refresh_token=${localStorage.refresh_token}&grant_type=refresh_token`
}
return fetch('/oauth/token', init)
.then(res => res.json())
.then(({ token_type, access_token, expires_in, refresh_token }) => {
localStorage.access_token = access_token
localStorage.refresh_token = refresh_token
return access_token
})
}
/** You supply a leadSeconds number or function that generates a number of seconds that the refresh should occur prior to the access token expiring */
const leadSeconds = () => {
/** Generate random additional seconds (up to 30 in this case) to append to the lead time to ensure multiple clients dont schedule simultaneous refresh */
const jitter = Math.floor(Math.random() * 30)
/** Schedule autorefresh to occur 60 to 90 seconds prior to token expiration */
return 60 + jitter
}
let start = autorefresh({ refresh, leadSeconds })
let cancel = () => {}
onAuthorize(access_token => {
cancel()
cancel = start(access_token)
})
onDeauthorize(() => cancel())
disclaimer: I am the maintainer 免责声明:我是维护者
更多推荐
所有评论(0)