在RESTful API中处理令牌更新/会话到期


17

我正在构建一个使用JWT令牌进行用户身份验证的RESTful API(由login端点发出,然后在所有标头中发送),并且需要在固定时间后刷新令牌(调用renew端点,该端点将返回更新的令牌) )。

用户的API会话有可能在令牌到期之前变得无效,因此我的所有端点都首先检查以下各项:1)令牌仍然有效,以及2)用户会话仍然有效。由于客户端将令牌存储在本地,因此无法直接使令牌无效。

因此,我所有的端点必须向我的客户发出两种可能情况的信号:1)是时候续订令牌了; 2)会话已变为无效,并且不再允许它们访问系统。我可以想到两种替代方法,当两种情况之一发生时,我的端点可以向其客户端发出信号(假设客户端可以适应任一选项):

  1. 如果会话无效,则返回http 401代码(未经授权),或者在令牌到期且需要调用renew端点时返回412代码(前提条件失败),这将返回200(正常)代码。
  2. 返回401,表示会话无效或令牌已过期。在这种情况下,客户端将立即调用该renew端点,如果它返回200,则刷新令牌,但是如果renew还返回401,则意味着该客户端不在系统之外。

您会推荐上述两种选择中的哪一种?哪一个会更标准,更容易理解和/或更RESTful?还是您会建议完全不同的方法?您发现这两种选择有明显的问题或安全隐患吗?如果您的答案包括支持您的观点的外部参考,则可以加分。

更新

伙计们,请关注一个真正的问题- 表示续订/会话无效的两个http代码替代方案中哪一个最好?不要介意我的系统使用JWT 服务器端会话的事实,这是我的API针对非常特定的业务规则的特性,而不是我正在寻求帮助的部分;)


假设令牌到期时间很短(约5分钟),那么在令牌到期之前用户会话将如何变得无效?
杰克

由于业务规则,系统的其他部分可能会使会话无效。
奥斯卡·洛佩斯

1
JWT用于身份证明,如“此请求被证明来自用户X”中所示。如果您的业务规则是“不再允许用户X与资源Y交互”,则应与JWT 分开检查。
杰克

@杰克!这正是我的观点,也是我必须使用附加的有状态层来保存会话信息的原因。普通的JWT,虽然可能不错,但并未削减工作量。
奥斯卡·洛佩斯

1
那您可能对我的回答感兴趣:)
杰克

Answers:


22

这听起来像是认证授权的案例。

JWT是关于请求始发者的加密签名声明。JWT可能包含诸如“此请求针对用户X”和“用户X具有管理员角色”之类的声明。通过密码,签名和TLS获取并提供此证明是身份验证的领域-证明您就是您所说的。

这些声明对您的服务器意味着什么-允许特定的用户和角色做什么-就是授权问题。可以用两种情况描述两者之间的差异。假设鲍勃想进入公司仓库的受限存储区,但首先他必须与名为吉姆的警卫打交道。

方案A-身份验证

  • 鲍勃:“你好,吉姆,我想输入受限存储空间。”
  • 吉姆:“你有徽章吗?”
  • 鲍勃:“不,算了。”
  • 吉姆:“对不起,朋友,没有徽章就不能入场。”

方案B-授权

  • 鲍勃:“你好吉姆,我想输入受限存储空间。这是我的徽章。”
  • 吉姆:“嗨,鲍勃,您需要获得2级许可才能进入此处。很抱歉。”

JWT到期时间是用于防止其他人窃取它们的身份验证设备。如果您所有的JWT都有五分钟的到期时间,那么它们被盗就没有什么大不了的,因为它们很快就会变得无用。但是,您讨论的“会话过期”规则听起来像是授权问题。状态上的某些变化意味着用户X不再被允许执行他们以前能够执行的操作。例如,用户Bob可能已经被解雇了-徽章上不再显示他是Bob无关紧要,因为仅仅成为Bob便不再授予他任何公司权限。

这两种情况具有不同的HTTP响应代码:401 Unauthorized403 Forbidden。不幸的是,命名为401的代码用于身份验证问题,例如丢失,过期或吊销凭证。403用于授权,服务器可以准确地知道您是谁,但是您无权执行您尝试做的事情。在删除用户帐户的情况下,尝试在端点处使用JWT进行操作将导致403禁止响应。但是,如果JWT过期,则正确的结果将是“ 401未经授权”。

常见的JWT模式是具有“长期”和“短期”令牌。长期令牌与短期令牌一样存储在客户端上,但是它们的范围有限,并且与授权系统一起使用才能获得短期令牌。顾名思义,寿命长的令牌具有非常长的有效期-您可以使用它们来请求新令牌,持续数天或数周。短暂令牌是您正在描述的令牌,在很短的有效时间内就可以与您的系统进行交互。长期令牌对于实现“记住我”功能很有用,因此您无需每五分钟提供一次密码即可获得一个新的短期令牌。

您正在描述的“会话无效”问题听起来与尝试使长寿的JWT无效相似,因为短寿的JWT很少存储在服务器端,而长寿的JWT则被跟踪以防需要撤销。在这样的系统中,尝试获取具有吊销的长期令牌的凭据将导致401未经授权,因为从技术上讲,用户可能能够获取凭据,但是他们使用的令牌不适合该任务。然后,当用户尝试使用其用户名和密码获取新的长期令牌时,如果系统将其踢出系统,则系统可能会以403 Forbidden进行响应。


3
这是我一直在寻找的指导,您为讨论带来了非常相关的见解-这是身份验证还是授权的情况,每种情况应以不同的方式处理。谢谢!
奥斯卡·洛佩斯

16

您的API会话根本不应该存在于RESTful世界中。RESTful操作应该是无状态的,会话包含状态,因此在RESTful世界中没有地位。

JWT应该是确定用户是否仍然有资格访问端点的唯一方法。会话绝对不起作用。如果是这样,则您没有RESTful API。

当您完全消除会话时(如果您要使用RESTful API则应该这样做),并且仅将JWT用作身份验证因素,则可以授权用户使用或不使用您的端点-在这种情况下,401 Unauthorized响应代码是适当的-并且应使用您正在使用的续约标识或其他标识来调用renew端点grant_type=refresh_token

更新:

从评论看来,您当前使用的JWT的验证流程似乎不正确。验证应该看起来像这样:

  Client        RESTful API      JWT Issuer
     |              |                |
     |----- 1. ---->|                | 
     |              |------ 2. ----->|-----
     |              |                | 3. |
     |              |<----- 4. ------|<----
-----|<---- 5. -----|                |
| 6. |              |                |
---->|----- 7. ---->|                |
     |              |------ 8. ----->|-----
     |              |                | 9. |
     |              |<----- 10. -----|<----
     |              |                |
     |              |------          |
     |              | 11. |          |
     |<---- 12. ----|<-----          |
     |              |                |
     .              .                .

1. Ask RESTful API for a JWT using login endpoint.
2. Ask Issuer to create a new JWT.
3. Create JWT.
4. Return JWT to the RESTful API.
5. Return JWT to Client.
6. Store JWT to append it to all future API requests.
7. Ask for data from API providing JWT as authorization.
8. Send JWT to Issuer for verification.
9. Issuer verifies JWT.
10. Issuer returns 200 OK, verification successful.
11. Retrieve and format data for Client.
12. Return data to Client.

服务器RESTful API必须检查作为授权发送的令牌的有效性。那不是的责任Client。看来您目前没有这样做。以这种方式实施JWT的验证,您根本不需要会话。


感谢您的回答。同意,使用会话不是100%RESTful的方法,但是如上所述,我需要在令牌过期之前拒绝对某些用户的访问。
奥斯卡·洛佩斯

2
@ÓscarLópez然后只需使用户使用的令牌无效即可。他们将不再能够使用提供的令牌访问API(该令牌现在将无效),并且您不需要会话。
安迪

1
令牌存储在客户端上,如何在那里使它们无效?我将不得不跟踪哪些是有效的……而这就是国家抬起头来的丑陋之处。有时这是不可避免的。
奥斯卡·洛佩斯

只要过期时间允许,恶意客户端就可以继续发送先前有效的令牌,但是我需要立即将其踢出系统-因此设置较短的续订时间也不是一种选择。
奥斯卡·洛佩斯

4
@Laiv我在记事本中制作了序列图。
安迪

1

因此,我承认,当您已经在会话中违反REST约定时,担心哪种方法最适合RESTful对我来说没有多大意义,但我知道满足您的业务需求。

从REST的角度来看,客户端要么通过身份验证,要么没有通过身份验证。该体系结构并不在乎为什么(即注入不必要的状态),因此要回答您的主要问题,我根本就没有更新的端点。登录的客户端将始终总是发送其JWT,服务器将始终对其进行验证,并根据操作200、201等通过发送适当的成功代码来接受它,或者在适当的情况下以401或403拒绝。

现在,JWT将与某种帐户相关联。该帐户可能被锁定或限制,因此令牌本身可能是有效的,但该操作在其他地方仍被拒绝。如果情况是用户帐户因业务规则而被锁定,则它仍然是401或403,具体取决于您要向客户提供多少信息(不同的企业对此有不同的看法)。

最后,如果您断言该帐户可能已解锁且有效,但是只需要撤销JWT,则我仍会坚持使用401或403并维护类似无效JWT的证书吊销列表的内容,您可以将其放入其中,只要它在JWT到期时进行清理即可(大多数数据库都有这样做的方式,或者您可以在应用程序代码中包含事件)。


jwt是无状态的。当您质疑其内容并针对db对其进行验证时,它就不再是无状态的了,因为对于有状态会话有更好的解决方案,它变得多余了
Stavm
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.