【问题标题】:Remove JWT on logout in Spring Application在 Spring 应用程序中注销时删除 JWT
【发布时间】:2018-07-31 03:27:21
【问题描述】:

我们正在尝试为基于 Spring REST 的应用程序遵循此代码库。 spring-boot-jwts

问题是我们无法在从服务器注销期间删除 JWT 令牌。当我们在网上查看时,我们知道唯一的方法是将 JWT 令牌列入黑名单,如Blacklisting 中给出的那样。是这样吗?

我们对基于令牌的身份验证有点陌生,请告诉我们是否有解决方案,例如在注销调用时使令牌过期等。

【问题讨论】:

    标签: spring spring-boot spring-security jwt


    【解决方案1】:

    长篇大论short,您必须建立一种机制来删除或使令牌无效manually 在注销时。

    是否应该存储 JWT 令牌?


    你应该问自己的问题是

    • 我需要将 JWT 令牌存储在数据库中吗?如果是这样,为什么?

    上述问题不一定能解决您的logout 问题,因为您仍然需要一种机制来invalidate 存储或不存储在database 中的令牌。

    not storing 数据库中的令牌的好处之一是您不必担心deleting 他们何时(无需维护或一些清理过程)

    • 他们的令牌过期
    • 他们的范围发生了变化
    • 用户(在password 流的情况下,我们不涉及其他flows)角色和权限在数据库中被降级或升级,因此,jwt 内部的内容已过时
    • 用户被删除
    • 用户退出(想知道这是否是删除令牌的充分理由)
    • 令牌被泄露(棘手的一个)
    • [添加其他案例]

    验证令牌的有效性?


    我确定您使用的是verify 端点,其目的是验证令牌是否为valid,但不必检查上述所有情况,这意味着您必须要么

    • 自定义verify 工作流程以添加更多custom checks
    • 在令牌被verified 用于signature validityexpiry time 和其他一些default checks 之前,您可以运行自己的custom checks,如果您的custom checks 已通过,则继续you shall not pass!

    那你有什么选择?


    嗯,除了blacklisting,你还可以做如下的事情

    使用内存存储

    只需将JWT令牌的uniquely-identifying-metadata作为key存入redis,并给它一个与JWT令牌到期时间相同的expiry time,以便令牌到期时self-destruct

    set key {replace_with_jwt_unique_identifier} ex {jwt_expiry_timestamp}
    

    风险:Redis 是内存存储,条目不会持久化。

    使用数据库

    不要使用 Redis 或不想冒险。您可以将数据库与自定义数据库表一起使用。一个单独的表,要么是

    • 与 JWT 记录相关并且有一个ON DELETE CASCADE
    • 与JWT记录无关,需自行维护

    发出令牌时,也会填充这个新的数据库表。

    常见的剩余步骤

    normal 请求带有 JWT 时,使用 JWT 查询 in-memory 存储或 database 表以查看是否存在记录。 对于in-memory 存储一个简单的existence 检查就绰绰有余了。 对于database table,您需要进行更多检查(即存在且未过期等),如果检查通过则让请求通过,否则you shall not pass!

    当出现logout request 时,如果是in-memory,存储只需删除key 并继续(如果找到),如果是database,您可以删除JWT 记录,该记录将级联到新表。

    何时进行自定义检查?

    嗯,你可以的

    • 首先使用自定义顶级过滤器或
    • 您可以扩展 verify 端点工作流来执行这些额外检查

    我使用的项目不需要在logout 上使令牌失效,所以我不必过这座桥。如果我的所有custom checks 都已通过,我确实必须扩展verify 端点以确保令牌有效。

    额外阅读材料

    除了您指出的教程。还有一些其他的 SO 问题也讨论了类似的问题。见

    What if JWT is stolen?
    How to destroy JWT on logout?
    More how to delete a JWT token?
    How to invlidate JWT when password changed
    Github issue - how to invalidate JWT
    Finally the best for the last - Invalidating JWT Web Tokens

    【讨论】:

      【解决方案2】:

      我们遇到了类似的问题,我们使用以下方法解决了它-

      1. 我们为每个 JWT 令牌添加一个请求 ID 以及过期时间。
      2. 创建会话时,我们会将此请求 ID 保存在数据库中,以针对其他令牌值及其到期时间。
      3. 当服务器发起注销时,我们将此请求标记为过期。
      4. 下次如果使用相同的令牌,我们通过验证请求ID确定这是一个过期的令牌。

      现在,在数据库中检查请求 ID 的成本很高,因此我们也使用内存缓存。

      【讨论】:

        【解决方案3】:

        JWT 令牌的优势在于它允许以一种自包含的方式在各方之间以 JSON 对象的形式安全地传输信息。此信息可以验证和信任,因为它经过数字签名。

        由于它是自包含的,因此您的任何资源服务器都可以验证它,而无需进行数据库查找或访问授权服务器。

        现在,如果您的要求是使令牌无效,我的建议是探索 Spring-Security 提供的 JDBC TokenStore。这样,所有发出的令牌都将存储在数据库中,当用户退出应用程序时,您可以使它们失效。为此,您可以公开服务以撤销令牌并适当地调用它

        @Resource(name="tokenServices")
        ConsumerTokenServices tokenServices;
        
        @RequestMapping(method = RequestMethod.POST, value = "/tokens/revoke/{tokenId:.*}")
        @ResponseBody
        public String revokeToken(@PathVariable String tokenId) {
            tokenServices.revokeToken(tokenId);
            return tokenId;
        }
        

        您的所有资源服务器都必须进行数据库查找以检查令牌的有效性

        【讨论】:

        • 感谢所有的指点。由于代码已经使用 JWT 作为令牌生成器,我们还必须添加 DB 来存储令牌。在后续请求中,我们将 JWT 令牌与 DB 中的令牌匹配,并且仅在它们匹配时才通过。
        猜你喜欢
        • 1970-01-01
        • 2016-04-01
        • 2011-05-15
        • 2013-08-23
        • 2011-09-19
        • 2018-09-23
        • 1970-01-01
        • 2019-03-13
        • 2020-08-11
        相关资源
        最近更新 更多