You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

Spring Boot应用中如何不通过抛出异常判断JWT Token是否过期

Great question—relying on exceptions for routine validation checks definitely gets messy, especially when you need to do this in multiple places. Let's break down how you can avoid exception-based checks for JWT expiration and implement a cleaner, reusable solution.

Solution 1: Directly Check Expiration from JWT Claims

Most JWT libraries let you parse the token's claims without automatically throwing an exception for expiration (you can disable that validation temporarily). You can then extract the exp (expiration time) claim and compare it against the current time manually.

Example with JJWT (Spring's common JWT library)

First, disable automatic expiration validation during parsing, then check the expiration date explicitly:

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.security.Keys;
import java.util.Date;

// Assume you have your signing key configured
byte[] signingKeyBytes = "your-signing-key-here".getBytes();

public boolean isTokenExpired(String token) {
    Claims claims = Jwts.parserBuilder()
            .setSigningKey(Keys.hmacShaKeyFor(signingKeyBytes))
            .ignoreExpiration() // Disable automatic expiration check
            .build()
            .parseClaimsJws(token)
            .getBody();

    Date expirationDate = claims.getExpiration();
    // Check if expiration date exists and is before current time
    return expirationDate != null && expirationDate.before(new Date());
}

Example with Nimbus JOSE + JWT

If you're using Nimbus, the approach is similar:

import com.nimbusds.jwt.JWT;
import com.nimbusds.jwt.JWTParser;
import com.nimbusds.jwt.JWTClaimsSet;
import java.util.Date;

public boolean isTokenExpired(String token) throws ParseException {
    JWT jwt = JWTParser.parse(token);
    JWTClaimsSet claimsSet = jwt.getJWTClaimsSet();
    Date expirationDate = claimsSet.getExpirationTime();
    
    return expirationDate != null && expirationDate.before(new Date());
}

Solution 2: Create a Custom Token Wrapper Class

To make this even more reusable, wrap the JWT claims in a custom class that encapsulates the expiration check (and other common token operations). This way, you can call a simple .isExpired() method anywhere in your code.

import io.jsonwebtoken.Claims;
import java.util.Date;
import java.util.Map;

public class CustomJwtToken {
    private final Claims claims;

    public CustomJwtToken(Claims claims) {
        this.claims = claims;
    }

    // Check if token is expired
    public boolean isExpired() {
        Date expiration = claims.getExpiration();
        return expiration != null && expiration.before(new Date());
    }

    // Helper method to get subject
    public String getSubject() {
        return claims.getSubject();
    }

    // Helper method to get your custom 'registry' claim
    @SuppressWarnings("unchecked")
    public Map<String, String> getRegistry() {
        return (Map<String, String>) claims.get("registry");
    }

    // Add other helper methods for claims you use regularly
}

Then, when you parse a token, create an instance of this wrapper:

CustomJwtToken createCustomToken(String token) {
    Claims claims = Jwts.parserBuilder()
            .setSigningKey(Keys.hmacShaKeyFor(signingKeyBytes))
            .ignoreExpiration()
            .build()
            .parseClaimsJws(token)
            .getBody();
    
    return new CustomJwtToken(claims);
}

Now, anywhere you need to check expiration, just call:

CustomJwtToken token = createCustomToken(requestToken);
if (token.isExpired()) {
    // Handle expired token logic
} else {
    // Proceed with authentication, etc.
}

Solution 3: Integrate with Spring Security Filter Chain

Since you're using Spring Boot, you can embed this logic into a custom authentication filter. This way, token expiration is checked once early in the request lifecycle, and you don't have to repeat the check in individual methods.

import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.web.filter.OncePerRequestFilter;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.security.Keys;
import java.io.IOException;
import java.util.Collections;

public class JwtAuthenticationFilter extends OncePerRequestFilter {
    private final byte[] signingKeyBytes;

    public JwtAuthenticationFilter(String signingKey) {
        this.signingKeyBytes = signingKey.getBytes();
    }

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        String token = extractTokenFromRequest(request);
        
        if (token != null) {
            try {
                Claims claims = Jwts.parserBuilder()
                        .setSigningKey(Keys.hmacShaKeyFor(signingKeyBytes))
                        .ignoreExpiration()
                        .build()
                        .parseClaimsJws(token)
                        .getBody();

                CustomJwtToken customToken = new CustomJwtToken(claims);
                
                if (customToken.isExpired()) {
                    response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Token has expired");
                    return;
                }

                // Set authentication in security context for downstream use
                UsernamePasswordAuthenticationToken authToken = new UsernamePasswordAuthenticationToken(
                        customToken.getSubject(), null, Collections.emptyList()
                );
                SecurityContextHolder.getContext().setAuthentication(authToken);
            } catch (Exception e) {
                // Handle invalid token (invalid signature, malformed, etc.)
                response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Invalid token");
                return;
            }
        }
        
        filterChain.doFilter(request, response);
    }

    private String extractTokenFromRequest(HttpServletRequest request) {
        // Extract token from Authorization header (Bearer token) or request parameter
        String bearerToken = request.getHeader("Authorization");
        if (bearerToken != null && bearerToken.startsWith("Bearer ")) {
            return bearerToken.substring(7);
        }
        return request.getParameter("token");
    }
}

Register this filter in your Spring Security configuration, and it will handle expiration checks automatically for all incoming requests.


内容的提问来源于stack exchange,提问作者wishyouwerehere

火山引擎 最新活动