【问题标题】:JAVA : How to invalidate all JWT token of particular user?JAVA:如何使特定用户的所有 JWT 令牌无效?
【发布时间】:2020-12-31 13:55:26
【问题描述】:

我有一个项目,目前有一个启用多用户会话的功能。但是现在我想让它像新用户登录时那样,然后该用户的所有其他会话都将失效。用户认证基于 JWT Token。那么如何才能使该用户的所有现有 JWT 令牌失效而只保留新令牌呢?

注意:目前我没有将 JWT 令牌存储在数据库中,我不希望这样,因为它会泄露安全性。

这是 JWTTokenUtils 的类,我从中生成令牌并对其进行验证。

@Component
public class JwtTokenUtil implements Serializable {

    public String getUsernameFromToken(String token) {
        return getClaimFromToken(token, Claims::getSubject);
    }

    public Date getExpirationDateFromToken(String token) {
        return getClaimFromToken(token, Claims::getExpiration);
    }

    public <T> T getClaimFromToken(String token, Function<Claims, T> claimsResolver) {
        final Claims claims = getAllClaimsFromToken(token);
        return claimsResolver.apply(claims);
    }

    private Claims getAllClaimsFromToken(String token) {
        return Jwts.parser()
                .setSigningKey(Base64.getEncoder().encodeToString(Constants.JWTToken.SIGNING_KEY.getBytes()))
                .parseClaimsJws(token)
                .getBody();
    }

    private Boolean isTokenExpired(String token) {
        final Date expiration = getExpirationDateFromToken(token);
        return expiration.before(new Date());
    }

    public String generateToken(String userId) {
        return doGenerateToken(userId);
    }

    private String doGenerateToken(String userId) {
        Claims claims = Jwts.claims().setSubject(userId);
        claims.put("scopes", Arrays.asList(new SimpleGrantedAuthority("ROLE_USER")));
        return Jwts.builder()
                .setClaims(claims)
                .setId(userId)
                .setIssuer(null)
                .setIssuedAt(new Date(System.currentTimeMillis()))
                .setExpiration(new Date(System.currentTimeMillis() + ACCESS_TOKEN_VALIDITY_SECONDS * 1000))
                .signWith(SignatureAlgorithm.HS256, Base64.getEncoder().encodeToString(Constants.JWTToken.SIGNING_KEY.getBytes()))
                .setHeaderParam("typ", "JWT")
                .compact();
    }

    public Boolean validateToken(String token, UserDetails userDetails) {
        final String username = getUsernameFromToken(token);
        return (username.equals(userDetails.getUsername())
                && !isTokenExpired(token));
    }
}

【问题讨论】:

  • 不能使 JWT 的设计失效不是事实吗?您说您不想将它们存储在数据库中,因为“泄露安全性”,您能详细说明一下吗?许多应用程序都使用这种方法,而不会产生重大的安全隐患。
  • 该项目已获得 PCI 安全标准委员会的保护和认证,为了匹配和遵循标准,我们无法存储它。
  • 您是否可以在 JWT 令牌中没有会话 ID,您确实存储了该会话 ID,并且当您想要使令牌无效时可以从数据库中删除?
  • 或者只为每个用户存储一个日期,并忽略在该日期之前发布的任何 JWT 令牌,即使它们尚未过期。
  • @tgdavies 最好不要将会话 ID 与 JWT 恕我直言混合。此外,使用缓存而不是数据库来存储此类状态(数据库不会很好地扩展)。

标签: java spring-boot authentication jwt jwt-auth


【解决方案1】:

为了做到这一点,您基本上需要在某处保持某种状态。您可以考虑的一种通用方法是维护应该被阻止的用户的黑名单缓存。在您的特定情况下,您还可以存储与每个用户关联的日期。对于每个传入的请求,您将首先快速点击黑名单缓存并确保传入的 JWT 的日期不会太旧。当然,您可以声明 exp 声明,因为可能传入的 JWT 一开始就已经过期。

这里的关键是使用缓存,比如Redis,它的查找速度非常快。您也可以使用数据库,但这会比一个好的缓存工具慢大约 100 倍。关于修剪缓存,当用户不再需要旧的 JWT 状态时,您可以删除他的条目。这可以通过在写入缓存条目时为缓存条目分配到期时间来实现自动化。

【讨论】:

    猜你喜欢
    • 2020-06-02
    • 2019-03-19
    • 2020-02-09
    • 2016-12-03
    • 2020-10-20
    • 2016-10-21
    • 2021-08-06
    • 2021-04-13
    相关资源
    最近更新 更多