我正在使用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,撤销由刷新令牌完成。但它似乎不起作用。
通常来说,最简单的答案是说你不能撤销JWT令牌,但这并不是真的。
诚实的答案是,支持JWT撤销的成本足够大,大多数情况下不值得考虑,或者干脆考虑替代方案。话虽如此,在某些情况下,您可能需要同时使用JWT和立即令牌撤销,因此我们将介绍需要采取的步骤,但首先我们将介绍一些概念。
JWT(学习JSON Web Tokens)只是指定了一个令牌格式,这个撤销问题也适用于通常称为自包含或按值令牌的任何格式。我喜欢后一种术语,因为它与按引用令牌形成良好对比。
在JWT大爆炸之前,我们已经在我们的认证系统中处理了令牌; 应用程序通常会在用户登录时创建一个会话标识符,然后将其用于使用户无需每次重复登录过程。这些会话标识符被用作服务器端存储的关键索引,如果这听起来像您最近读到的某些内容,那么您是正确的,这确实属于按引用令牌。按值令牌 - 关联信息(包括令牌生存期)包含在令牌本身中,可以验证该信息源自可信源(数字签名解救了我们)
按引用令牌 - 关联信息存储在服务器端存储中,然后使用令牌值作为键进行获取;由于是服务器端存储,所以关联信息被隐式信任
(jti,exp)
,并分发所有这些配对,而服务器可以独立于任何集中式存储从exp
中删除它们。在可扩展性方面表现非常出色,但在吊销jti
ID方面仍具有有状态的“反会话”。 - Brian CannardJWT无法被撤销。
但是这里有一种替代方案,称为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上提供了一个示例应用程序。
针对谷歌员工:
关于按引用和按值传递令牌的答案已经很好地解决了这个问题。对于那些将来会遇到这个问题的人们。
如何在RS端实现撤销:
简而言之:
获取一个缓存或数据库,该缓存或数据库对所有验证令牌的后端服务实例都可见。当收到新的令牌以进行撤销时,如果它是有效的(即根据您的jwt验证算法进行验证),则获取exp和jti声明,并将jti保存到缓存中,直到达到exp。然后在unixNow变成> exp后,使缓存中的jti过期。
然后在其他端点上进行授权时,每次检查给定的jti是否与此缓存中的某些内容匹配,如果是,则出现403错误,表示令牌已被撤销。一旦它过期,您的验证算法就会出现常规的令牌过期错误。
附注:通过仅保存jti在缓存中,您使这些数据对任何人都无用,因为它只是一个唯一的令牌标识符。
JWT吊销的最佳解决方案是使用短期过期时间、刷新并将已发行的JWT令牌保存在共享的离线缓存中。例如,使用Redis特别容易,因为您可以将缓存键设置为令牌本身(或令牌的哈希值),并指定到期时间,以便自动驱逐令牌。
我找到了解决问题的一种方法,如何使用Java过期已生成的现有JWT令牌?
在这种情况下,我们需要使用任何DB或内存,其中:
步骤1:当为用户第一次生成令牌时,请将其与令牌及其“issuedAt()”时间一起存储在db中。
我以JSON格式将其存储在DB中,如下所示:
Ex: {"username" : "username",
"token" : "token",
"issuedAt" : "issuedAt"
}
步骤2:一旦您收到同一用户的Web服务请求以验证令牌,请从令牌中提取“issuedAt()”时间戳,并将其与存储的(DB /内存)发行时间戳进行比较。
步骤3:如果存储的发行时间戳是新的(使用after() / before()方法),则返回该令牌无效(在这种情况下,我们实际上没有使令牌过期,但我们停止使用该令牌访问权限)。
这是我解决问题的方法。