简体   繁体   中英

JAVA : How to invalidate all JWT token of particular user?

I have a project where currently there is a functionality where multiple user session is enabled. But now I want to make it something like when a new user logged in, then all other sessions of that user will be invalidated. User authentication is based on JWT Token. So how can I invalidate all the existing JWT Tokens of that user and keep only the new one?

Note: Currently I am not storing JWT Token in Database and I don't want that because it leaks the security.

Here is the class for JWTTokenUtils from where I generate the token and validate it.

@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));
    }
}

In order to do this, you basically need to persist some sort of state, somewhere. One general approach which you may consider would be to maintain a blacklist cache of users who should be blocked. In your particular case, you could also store a date associated with each user. For each incoming request, you would first quickly hit the blacklist cache and make sure that the incoming JWT's date were not too old. Of course, you could assert the exp claim, because perhaps the incoming JWT be already expired in the first place.

The key point here is to use a cache , like Redis, which has very fast lookups. You could also use a database, but that would be about 100 times slower than a good cache tool. Regarding pruning the cache, when a user no longer requires the old JWT state, you may delete his entry. This can be automated, perhaps, by assigning an expiry to the cache entry when you write it.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM