我正在使用Spring Security OAuth2和JWT令牌。我的问题是:我如何撤销JWT令牌?
正如这里提到的http://projects.spring.io/spring-security-oauth/docs/oauth2.html,撤销是通过刷新令牌完成的。但它似乎没有用。
一般来说,最简单的答案就是说你不能撤销JWT令牌,但事实并非如此。诚实的答案是,支持JWT撤销的成本足够大,不值得大部分时间,或者明显重新考虑替代JWT。
话虽如此,在某些情况下,您可能需要JWT和立即令牌撤销,所以让我们看看它会采取什么,但首先我们将介绍一些概念。
JWT(Learn JSON Web Tokens)只是指定一种令牌格式,这种撤销问题也适用于通常称为自包含或按值令牌的任何格式。我喜欢后一种术语,因为它与副参考标记形成了鲜明的对比。
按值令牌 - 相关信息(包括令牌生存期)包含在令牌本身中,并且可以将信息验证为源自可信来源(救援的数字签名)
引用令牌 - 相关信息保存在服务器端存储上,然后使用令牌值作为密钥获取;作为服务器端存储,相关信息是隐式信任的
在JWT Big Bang之前,我们已经在我们的身份验证系统中处理了令牌;应用程序在用户登录时创建会话标识符通常会被使用,这样用户就不必每次都重复登录过程。这些会话标识符被用作服务器端存储的关键索引,如果这听起来类似于您最近阅读的内容,那么您确实将其归类为引用标记。
使用相同的类比,理解副参考令牌的撤销是微不足道的;我们只是删除映射到该密钥的服务器端存储,下次提供密钥时它将无效。
对于按值标记,我们只需要执行相反的操作。当您请求撤销令牌时,您存储了一些允许您唯一标识该令牌的内容,以便下次收到该令牌时,您还可以检查它是否已被撤销。如果您已经在考虑这样的事情无法扩展,请记住,您只需要存储数据,直到令牌到期为止,在大多数情况下,您可能只是存储令牌的哈希值,因此它总是存在是一个已知的大小。
作为最后一点,并以OAuth 2.0为中心,撤销按值访问令牌目前尚未标准化。尽管如此,OAuth 2.0令牌撤销明确指出,只要授权服务器和资源服务器都同意自定义处理方式,它仍然可以实现:
在前一种情况(自包含令牌)中,当需要立即访问令牌撤销时,可以使用授权服务器和资源服务器之间的一些(当前非标准化的)后端交互。
如果您同时控制授权服务器和资源服务器,则很容易实现。另一方面,如果您将授权服务器角色委派给像Auth0这样的云提供商或者像Spring OAuth 2.0这样的第三方组件,那么您很可能需要采用不同的方法,因为您可能只会获得已经标准化的内容。
一个有趣的参考
本文解释了另一种方法:Blacklist JWT它包含一些有趣的实践和模式,其次是RFC7523
这是一个名为JWT old的解决方案,用于新的交换模式。
因为我们不能在到期时间之前使发布的令牌无效,所以我们总是使用短时令牌,例如30分钟。当令牌过期时,我们使用旧令牌交换新令牌。关键点是一个旧令牌只能交换一个新令牌。
在中心auth服务器中,我们维护一个这样的表:
table auth_tokens(
user_id,
jwt_hash,
expire
)
user_id包含在JWT字符串中。 jwt_hash是整个JWT字符串的哈希值,例如SHA256。 expire字段是可选的。
以下是工作流程:
要连续使用令牌,合法用户和黑客都需要连续交换新令牌,但只有一个可以成功,当一个失败时,都需要在下次交换时再次登录。
因此,如果黑客获得令牌,它可以短时间使用,但如果合法用户下次交换新签名,则无法换新签名,因为令牌有效期很短。这种方式更安全。
如果没有黑客,普通用户也需要定期交换新令牌,比如每30分钟,这就像自动登录一样。额外负载不高,我们可以调整应用程序的到期时间。
这并没有完全回答你关于Spring框架的问题,但是这篇文章讨论了为什么如果你需要撤销JWT的能力,你可能不想首先使用JWT,而是使用常规,不透明的承载令牌。
撤销JWT的一种方法是利用分布式事件系统,该系统在刷新令牌被撤销时通知服务。当撤销刷新令牌并且其他后端/服务侦听事件时,身份提供者广播事件。当收到事件时,后端/服务会更新本地缓存,该缓存维护一组已撤销刷新令牌的用户。
然后,每当验证JWT以确定是否应该撤销JWT时,都检查该高速缓存。这完全基于JWT的持续时间和各个JWT的到期时刻。
这篇文章Revoking JWTs说明了这个概念,并在Github上有一个示例应用程序。
以下是撤销JWT访问令牌的步骤:
如果您需要更多详细信息,请告诉我,我也可以分享代码。