我正在使用Spring Security OAuth2和JWT令牌。我的问题是:如何撤销JWT令牌?
如此处 http://projects.spring.io/spring-security-oauth/docs/oauth2.html所述,吊销是通过刷新令牌完成的。但这似乎不起作用。
我正在使用Spring Security OAuth2和JWT令牌。我的问题是:如何撤销JWT令牌?
如此处 http://projects.spring.io/spring-security-oauth/docs/oauth2.html所述,吊销是通过刷新令牌完成的。但这似乎不起作用。
Answers:
通常,最简单的答案是说您无法撤消JWT令牌,但这不是真的。诚实的答案是,支持JWT撤销的成本足够大,以致于大多数时候都不值得,或者明确地重新考虑JWT的替代方案。
话虽如此,在某些情况下,您可能需要JWT和立即的令牌吊销,因此让我们仔细研究一下它会发生的情况,但是首先我们将介绍一些概念。
JWT(学习JSON Web令牌)仅指定令牌格式,此吊销问题也将应用于通常称为自包含或按值令牌的任何格式。我喜欢后一种术语,因为它与副引用标记形成了很好的对比。
按值令牌-令牌本身包含相关信息,包括令牌生存期,并且可以验证该信息是否源自受信任的源(用于救援的数字签名)
引用令牌-关联信息保存在服务器端存储中,然后使用令牌值作为键获得该信息;作为服务器端存储,关联的信息被隐式信任
在JWT大爆炸之前,我们已经在身份验证系统中处理过令牌。应用程序通常在用户登录时创建会话标识符,然后使用该会话标识符,这样用户不必每次都重复登录过程。这些会话标识符被用作服务器端存储的关键索引,如果这听起来与您最近阅读的内容相似,那么您是对的,的确将其归为按引用标记。
使用相同的类比,了解按引用令牌的撤销是微不足道的。我们只是删除映射到该密钥的服务器端存储,而下次提供该密钥将无效。
对于按值代币,我们只需要执行相反的操作即可。当您请求吊销令牌时,会存储一些东西,使您可以唯一地标识该令牌,以便下次收到令牌时,您还可以检查它是否已被撤销。如果您已经在考虑像这样的事情将无法扩展,请记住,您只需要存储数据,直到令牌到期为止,在大多数情况下,您可能只需要存储令牌的哈希值,这样就可以始终是已知大小的东西。
最后要注意的是,以OAuth 2.0为中心,按值访问令牌的撤销目前尚未标准化。但是,OAuth 2.0令牌撤销明确指出,只要授权服务器和资源服务器都同意使用自定义方式来处理此问题,仍可以实现:
在前一种情况(自包含令牌)中,当需要立即访问令牌吊销时,可以使用授权服务器和资源服务器之间的某些(当前未标准化)后端交互。
如果您同时控制授权服务器和资源服务器,则非常容易实现。另一方面,如果将授权服务器角色委派给Auth0之类的云提供商或Spring OAuth 2.0之类的第三方组件,则您很可能需要采用不同的方法,因为您可能只会得到已经标准化的内容。
一个有趣的参考
JWT无法撤销。
但是,这里有一个称为JWT的替代解决方案,用于新的交换模式。
由于我们无法在到期时间之前使已发行的令牌失效,因此我们始终使用短时令牌,例如30分钟。当令牌过期时,我们使用旧令牌交换新令牌。关键的一点是一个老令牌可以换取一个新的令牌只。
在中心身份验证服务器中,我们维护一个像这样的表:
table auth_tokens(
user_id,
jwt_hash,
expire
)
JWT字符串中包含的user_id。jwt_hash是整个JWT字符串的哈希值,例如SHA256。expire字段是可选的。
以下是工作流程:
要连续使用令牌,合法用户和黑客都需要连续交换新令牌,但是只有一个可以成功,如果一个失败,则都需要在下一次交换时再次登录。
因此,如果黑客获得了令牌,那么令牌可以使用很短的时间,但是如果合法用户下次交换新令牌,则该令牌就不能使用,因为令牌的有效期很短。这样更安全。
如果没有黑客,普通用户也需要定期(例如每30分钟)交换新令牌,就像自动登录一样。额外的负载不高,我们可以调整应用程序的到期时间。
这并不能完全回答您有关Spring框架的问题,但这是一篇文章,讨论了为什么如果您需要撤销JWT的功能,那么您可能不希望首先使用JWT,而是使用常规的,不透明的Bearer令牌。
撤销JWT的一种方法是利用分布式事件系统,该系统在刷新令牌已被撤销时通知服务。当刷新令牌被吊销并且其他后端/服务侦听该事件时,身份提供者广播事件。接收到事件后,后端/服务将更新本地缓存,该缓存维护一组其刷新令牌已被撤销的用户。
每当验证JWT以确定是否应撤销JWT时,便会检查此缓存。这全部基于JWT的持续时间和各个JWT的到期时间。
本文名为Revoking JWTs,阐述了这一概念,并在Github上提供了一个示例应用程序。
对于Google员工:
如何存储JWT令牌并将其引用给数据库中的用户?在执行JWT比较之后,通过使用附加的数据库联接扩展后端应用程序中的Guards / Security Systems,您实际上可以通过从数据库中删除或软删除来“撤消”它。
我找到了解决问题的一种方法,即如何使使用Java生成的现有JWT令牌过期?
在这种情况下,我们需要使用任何数据库或内存,
第1步:首次为用户生成令牌后,立即将其与令牌一起存储在db中,并且该时间为“ issueAt() ”。
我以JSON格式将其存储在数据库中,
例如: { "username" : "username",
"token" : "token",
"issuedAt" : "issuedAt"
}
第2步:一旦您获得了具有要验证的令牌的同一用户的Web服务请求,便从令牌中获取“ issueAt() ”时间戳,并将其与存储的(DB /内存)发布的时间戳进行比较。
步骤3:如果存储的已发布时间戳是新的(使用after()/ before()方法),则返回令牌无效(在这种情况下,我们实际上并未使令牌到期,但我们将停止提供对该令牌的访问权限)。
这就是我解决问题的方式。