JWT Token无效时如何返回自定义响应?

问题描述 投票:0回答:1

当 JWT 令牌无效时,我尝试返回自定义响应。

我知道 Spring Security 异常是在控制器开始工作之前抛出的。因此,我尝试编写自己的“CustomBearerAuthenticationEntryPoint”类来实现“AuthenticationEntryPoint”。但在这个课程中,我得到 *Cannot find bean with qualifier 'handlerExceptionResolver' *.

package ila.ila_backend.security;

import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.web.AuthenticationEntryPoint;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerExceptionResolver;

import java.io.IOException;

@Component
public class CustomBearerAuthenticationEntryPoint implements AuthenticationEntryPoint {

    private final HandlerExceptionResolver resolver;


    public CustomBearerAuthenticationEntryPoint(@Qualifier("handlerExceptionResolver") HandlerExceptionResolver resolver) {
        this.resolver = resolver;
    }

    @Override
    public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException) throws IOException, ServletException {
        this.resolver.resolveException(request, response, null, authException);
    }

}

这是我的 *CustomBearerTokenAccesDeniedHandler * 类:

package ila.ila_backend.security;

import jakarta.servlet.ServletException;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.web.access.AccessDeniedHandler;
import org.springframework.stereotype.Component;
import org.springframework.web.servlet.HandlerExceptionResolver;

import java.io.IOException;

@Component
public class CustomBearerTokenAccesDeniedHandler implements AccessDeniedHandler {
    private final HandlerExceptionResolver resolver;

    public CustomBearerTokenAccesDeniedHandler(@Qualifier("handlerExceptionResolver") HandlerExceptionResolver resolver) {
        this.resolver = resolver;
    }

    @Override
    public void handle(HttpServletRequest request, HttpServletResponse response, AccessDeniedException accessDeniedException) throws IOException, ServletException {
        this.resolver.resolveException(request,response,null,accessDeniedException);
    }
}

我的SecurityConfig类:

package ila.ila_backend.security;
import jakarta.servlet.DispatcherType;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.web.cors.CorsConfiguration;
import org.springframework.web.cors.UrlBasedCorsConfigurationSource;
import org.springframework.web.filter.CorsFilter;

@Configuration
@EnableWebSecurity
public class SecurityConfig {


    private JwtAuthenticationEntryPoint handler;
    private final CustomBearerAuthenticationEntryPoint customBearerTokenAccessEntryPoint;
    private final CustomBearerTokenAccesDeniedHandler customBearerTokenAccesDeniedHandler;

    public SecurityConfig(UserDetailsServiceImpl userDetailsService, JwtAuthenticationEntryPoint handler, CustomBearerAuthenticationEntryPoint customBearerTokenAccessEntryPoint, CustomBearerTokenAccesDeniedHandler customBearerTokenAccesDeniedHandler) {

        this.handler = handler;
        this.customBearerTokenAccessEntryPoint = customBearerTokenAccessEntryPoint;
        this.customBearerTokenAccesDeniedHandler = customBearerTokenAccesDeniedHandler;
    }

    @Bean
    public JwtAuthenticationFilter jwtAuthenticationFilter() {
        return new JwtAuthenticationFilter();
    }

    @Bean
    public PasswordEncoder passwordEncoder() {
        return new BCryptPasswordEncoder();
    }

    @Bean
    public CorsFilter corsFilter() {
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        CorsConfiguration config = new CorsConfiguration();
        config.setAllowCredentials(true);
        config.addAllowedOrigin("*");
        config.addAllowedHeader("*");
        config.addAllowedMethod("OPTIONS");
        config.addAllowedMethod("HEAD");
        config.addAllowedMethod("GET");
        config.addAllowedMethod("PUT");
        config.addAllowedMethod("POST");
        config.addAllowedMethod("DELETE");
        config.addAllowedMethod("PATCH");

        source.registerCorsConfiguration("/**", config);
        return new CorsFilter(source);
    }

 @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
     http
             //.formLogin().failureHandler()
             .csrf(csrf -> csrf.disable())
             .authorizeHttpRequests(authorize -> {
                 authorize.requestMatchers("/api/projects/getProjects").authenticated();
                 authorize.requestMatchers("/api/activities/getActivities").authenticated();
                 authorize.requestMatchers("/api/participants/getSelectedParticipants").authenticated();
                 authorize.dispatcherTypeMatchers(DispatcherType.ERROR).permitAll();
                 authorize.anyRequest().permitAll();

             })
             .exceptionHandling(exceptionHandling ->
                     exceptionHandling.
                             authenticationEntryPoint(this.customBearerTokenAccessEntryPoint)
                             .accessDeniedHandler(this.customBearerTokenAccesDeniedHandler))
             .sessionManagement(sessionManagement -> sessionManagement.sessionCreationPolicy(SessionCreationPolicy.STATELESS))
             .addFilterBefore(jwtAuthenticationFilter(), UsernamePasswordAuthenticationFilter.class);


     return http.build();
 }

    }

我的控制器:

@GetMapping("/getProjects")
    public ResponseEntity<ProjectsApiResponse<ProjectsResponse>> getProjects(@RequestHeader("Authorization") String token) {
        String tokenWithoutPrefix = token.substring("Bearer ".length());

        // Validate the token before proceeding
        if (!jwtTokenManager.validateToken(tokenWithoutPrefix)) {
            throw new UnauthorizedUserException("Invalid JWT");
        }

        Long userId = jwtTokenManager.getUserIdFromToken(tokenWithoutPrefix);
        System.out.println("Extracted User ID: " + userId);

        List<Projects> projects = projectsService.getProjectsByUserId(userId);

        List<ProjectsResponse> projectsResponseList = new ArrayList<>();
        for (Projects project : projects) {
            ProjectsResponse projectResponse = new ProjectsResponse(project.getId(), project.getName());
            projectsResponseList.add(projectResponse);
        }

        ProjectsApiResponse<ProjectsResponse> response = new ProjectsApiResponse<>("success", projectsResponseList);
        return new ResponseEntity<>(response, HttpStatus.OK);
    }

验证令牌:

@Override
    public boolean validateToken(String token) {

        try {
            Jwts.parserBuilder().setSigningKey(secretKey).build().parseClaimsJws(token);
            return true;
        } catch (SignatureException e) {
            LOGGER.error("Invalid JWT signature: " + e.getMessage());

        } catch (MalformedJwtException e) {
            LOGGER.error("Malformed JWT: " + e.getMessage());

        } catch (ExpiredJwtException e) {
            LOGGER.error("Expired JWT: " + e.getMessage());

        } catch (UnsupportedJwtException e) {
            LOGGER.error("Unsupported JWT: " + e.getMessage());

        } catch (IllegalArgumentException e) {
            LOGGER.error("JWT claims string is empty: " + e.getMessage());

        }
        return false;
    }

我的异常处理程序(在 GlobalExceptionHandler 类中):

@ExceptionHandler(InvalidBearerTokenException.class)
    @ResponseStatus(HttpStatus.UNAUTHORIZED)
    public ErrorMessage handleInvalidBearerTokenException (InvalidBearerTokenException ex) {
        return new ErrorMessage("error", "The access token provided is expired, invalid or malformed.");
    }

在这种情况下,当我写入无效的 JWT 令牌时,我收到“500 内部服务器错误”且正文为空。我期待看到我的自定义回复。

我已经附上了我所有的相关课程(如果你想看,我可以分享其他代码)。我真的需要你的帮助来解决这个问题。预先感谢。

Here is my classes:

spring-boot exception spring-security jwt authorization
1个回答
0
投票

首先创建一个自定义异常处理类并编写自定义异常方法。 (你已经有了)

@ControllerAdvice
public class CustomExceptionHandler  {
    @ExceptionHandler(value = {ExpiredJwtException.class})
    public ResponseEntity<Object> handleExpiredJwtException(ExpiredJwtException ex, WebRequest request) {
       var errMsg = new ErrorMessage("error", "Token provided is expired");
        return new ResponseEntity<Object>(errMsg, HttpStatus.UNAUTHORIZED);
    }

    @ExceptionHandler(value = {InvalidBearerTokenException.class})
    public ResponseEntity<Object> invalidBearerTokenException(ExpiredJwtException ex, WebRequest request) {
       var errMsg = new ErrorMessage("error", "The access token provided is expired, invalid or malformed.");
        return new ResponseEntity<Object>(errMsg, HttpStatus.UNAUTHORIZED);
    }
}

// Add logic under this filter
@Component
public class JwtAuthenticationFilter extends OncePerRequestFilter {

    // @Autowired others Bean If required
     
    @Autowired
    private JwtService jwtService;

    @Autowired
    @Qualifier("handlerExceptionResolver")
    private HandlerExceptionResolver resolver;

    @Override
    protected void doFilterInternal(
            @NonNull HttpServletRequest request,
            @NonNull HttpServletResponse response,
            @NonNull FilterChain filterChain
    ) throws ServletException, IOException {
        try {
            // Put your JWT filter codes under try catch block
            // Provide an example
            final var jwt = jwtService.resolveToken(request);

        } catch (ExpiredJwtException ex) {
            // Catch exception as you like
            resolver.resolveException(request, response, null, ex);
        }
        catch (InvalidBearerTokenException ex) {
            // Catch exception as you like
            resolver.resolveException(request, response, null, ex);
        }
    }
}

尝试使用此方法,如果您有任何问题请告诉我。因为它正在处理我的代码。

© www.soinside.com 2019 - 2024. All rights reserved.