spring-security 如何正确处理JwtException?

kokeuurv  于 2022-11-11  发布在  Spring
关注(0)|答案(3)|浏览(182)

当令牌过期时,我收到这样的错误

io.jsonwebtoken.JwtException: JWT expired at 2020-09-18T19:08:08Z. Current time: 2020-09-22T20:26:51Z, a difference of 350323563 milliseconds.  Allowed clock skew: 0 milliseconds.

我创建了一个实现AuthenticationEntryPoint的类

@Component
public class CustomAuthenticationEntryPoint implements AuthenticationEntryPoint {

    @Override
    public void commence(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse,
                         AuthenticationException e) throws IOException, ServletException {
        ObjectMapper mapper = new ObjectMapper();
        ErrorDetails errorDetails = ErrorDetails.builder()
                .details(String.valueOf(e.getClass()))
                .message("JWT has expired")
                .timestamp(DateTimeFormatter.ofPattern("MM-dd-yyyy HH:mm:ss", Locale.ENGLISH)
                        .format(LocalDateTime.now()))
                .build();
        httpServletResponse.setStatus(HttpStatus.UNAUTHORIZED.value());
        httpServletResponse.setContentType("application/json");
        httpServletResponse.setCharacterEncoding("UTF-8");
        httpServletResponse.getWriter().write(mapper.writeValueAsString(errorDetails));
    }

在《 Postman 》中

{
    "timestamp": "09-22-2020 20:26:51",
    "message": "JWT has expired",
    "details": "class org.springframework.security.authentication.InsufficientAuthenticationException"
}

配置方法窗体SecurityConfig

@Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .cors()
                .and()
                .csrf()
                .disable()
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS)
                .and()
                .exceptionHandling().authenticationEntryPoint(entryPoint)
                .and()
                .addFilterAfter(new JwtAuthorizationFilter(authenticationManager(), secret),
                        UsernamePasswordAuthenticationFilter.class)
                .authorizeRequests()
                .antMatchers("/api/credit/**").hasRole("USER")
                .antMatchers("/api/auth/login").permitAll()
                .anyRequest().denyAll();
        http
                .headers()
                .addHeaderWriter(new StaticHeadersWriter("Content-Type", "application/json"));
    }

有人可以建议我如何正确处理IDE中出现的异常。

解决方案

在Jwt授权筛选器中

catch (ExpiredJwtException e) {
            request.setAttribute("expired", e.getMessage());
        }

在自定义身份验证入口点中

if(httpServletRequest.getAttribute("expired") != null){
            errorDetails.setMessage(String.valueOf(httpServletRequest.getAttribute("expired")));
        }
qlzsbp2j

qlzsbp2j1#

Spring Security 5.1+内置了对JWT的支持。
您可以配置Spring Security来查找JWT,而不是连接您自己的自定义过滤器:

http
    // ...
    .oauth2ResourceServer((oauth2) -> oauth2
        .authenticationEntryPoint(myCustomEntryPoint)
        .jwt()
    )
    // ... no need for a custom filter

由于您有一种自定义的方法来处理JWT,因此可以发布自己的JwtDecoder实现:

@Bean
public JwtDecoder jwtDecoder() {
    return (encodedJwt) -> {
        // verify the JWT
    }
}

Spring Security的不记名令牌过滤器将在适当的时间调用您的AuthenticationEntryPoint,并减少您的应用程序的一些定制。

ldioqlga

ldioqlga2#

下面是我们如何捕获JwtException(io.jsonwebtoken.ExpiredJwtException)。
关键部件包括:

  • 在配置UsernamePasswordAuthenticationFilter之前配置JWTFilter
  • 解析JWT标记并捕获ExpiredJwtException
  • ExpiredJwtException Package 在AuthenticationException的一个实现中并重新引发,以便在CustomAuthenticationEntryPoint中处理它。请注意,org.springframework.security.web.access.ExceptionTranslationFilter#handleSpringSecurityException仅对AuthenticationExceptionAccessDeniedException委托AuthenticationEntryPoint
    JWT筛选器
@Slf4j
public class JWTFilter extends GenericFilterBean {

    @Override
    public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) {
        HttpServletRequest httpServletRequest = (HttpServletRequest) servletRequest;

        String jwt = resolveToken(httpServletRequest);

        try {
            Claims claims = Jwts.parserBuilder().setSigningKey(key).build()
                    .parseClaimsJws(jwt).getBody();

            //everything is valid !!, let's login
            Authentication authentication = getAuthentication(claims);
            SecurityContextHolder.getContext().setAuthentication(authentication);
        } catch (ExpiredJwtException e) {
            log.error("Expired JWT token.", e);
            //HANDLE IT HERE::::: wrap ExpiredJwtException in AuthenticationException and rethrow Exception
           throw new CredentialsExpiredException("Expired jwt credentials ", e);

        } catch (OtherExceptions e) {
            log.info("JWT token compact of handler are invalid.");
            log.trace("JWT token compact of handler are invalid trace: ", e);
        }

        //finally filter it through
        filterChain.doFilter(servletRequest, servletResponse);
    }

}
uujelgoq

uujelgoq3#

//您可以简单地用try块包围Filter类并捕获此//异常

catch (Exception exception){
                log.error("Error logging in : {} ", exception.getMessage());
                response.setHeader("error",exception.getMessage());
                response.setStatus(FORBIDDEN.value());
                Map<String,String > error = new HashMap<>();
                error.put("error_message",exception.getMessage());
                response.setContentType(APPLICATION_JSON_VALUE);
                new ObjectMapper().writeValue(response.getOutputStream(),error);
            }

//然后在验证标记catch的util类中//

public Boolean validateToken(String token, UserDetails userDetails, HttpServletRequest request)  {
        try {
            final String username = extractUsername(token);
            log.info("Username " + username.equals(userDetails.getUsername()));
            return (username.equals(userDetails.getUsername()) && !isTokenExpired(token));
        } catch (ExpiredJwtException expiredJwtException) {
            log.info("Utils :: validateToke :: token Exception -> expired!");
            request.setAttribute("expired",expiredJwtException.getMessage());
            throw new ExpiredJwtException(expiredJwtException.getHeader(), expiredJwtException.getClaims(), "Expired JWT token");

//按照这些步骤操作后,您将在中获得所需的响应。

相关问题