AuthenticationEntryPoint 不处理某些异常

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

我正在使用 Spring Boot 创建一个 API 网关,我使用 jwt 令牌来验证用户会话,并且我在 SpringSecurity 中遇到了这个问题,所以这是我的 SecurityFilterChain

@Configuration
@EnableWebSecurity
public class SecurityConfig {
    @Value("${cognito.issuer}")
    private String jwkIssuerUri;

    @Autowired
    private JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint;

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
        http
                .csrf().disable()
                .exceptionHandling( exceptions -> exceptions
                        .authenticationEntryPoint(jwtAuthenticationEntryPoint))
                .authorizeRequests(authorizeRequests ->
                        authorizeRequests
                                .antMatchers("/auth/callback").permitAll()
                                .anyRequest().authenticated()
                ).oauth2ResourceServer(oauth2ResourceServer ->
                        oauth2ResourceServer.jwt(jwt ->
                                jwt.decoder(jwtDecoder())
                        )
                );
        return http.build();
    }

    @Bean
    public JwtDecoder jwtDecoder() {
        return JwtDecoders.fromOidcIssuerLocation(jwkIssuerUri);
    }

}

如您所见,我正在尝试通过实现 AuthenticationEntryPoint 来处理验证异常,这是我的课程:

@Component
public class JwtAuthenticationEntryPoint implements AuthenticationEntryPoint {

    private static final Logger logger = LoggerFactory.getLogger(JwtAuthenticationEntryPoint.class);
    @Override
    public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException)
        throws IOException {
        logger.debug("Commence method called. Handling exception.");
        response.setContentType("application/json");
        response.setCharacterEncoding("UTF-8");
        if("ExpiredJwtException".equals(authException.getClass().getSimpleName())) {
            logger.debug("Authentication error:\n", authException);
            response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
            response.getWriter().write(String.format("{\"error\": \"%s\", \"message\": \"%s\"}",
                    HttpServletResponse.SC_UNAUTHORIZED, "Provided authorization token is expired"));
        } else if("InsufficientAuthenticationException".equals(authException.getClass().getSimpleName())) {
            logger.debug("Athentication error:\n", authException);
            response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
            response.getWriter().write(String.format("{\"error\": \"%s\", \"message\": \"%s\"}",
                    HttpServletResponse.SC_UNAUTHORIZED, "Authorization token must be provided to reach this endpoint"));
        } else {
            logger.debug("Authentication error:\n", authException);
            response.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
            response.getWriter().write(String.format("{\"error\": \"%s\", \"message\": \"%s\"}",
                    HttpServletResponse.SC_UNAUTHORIZED, "Cannot validate the token"));
        }
    }
}

现在我能够处理

InsufficientAuthenticationException
但其他异常,比如
ExpiredJwtException
不是由此类处理的,但它们正在由 spring security 处理,这里是此案例的日志:

2024-05-09 15:12 |DEBUG| org.springframework.security.web.context.HttpSessionSecurityContextRepository.saveContext()
Did not store empty SecurityContext
2024-05-09 15:12 |DEBUG| org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter()
Cleared SecurityContextHolder to complete request
2024-05-09 15:13 |DEBUG| org.springframework.security.web.FilterChainProxy.doFilterInternal()
Securing GET /test
2024-05-09 15:13 |DEBUG| org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter()
Set SecurityContextHolder to empty SecurityContext
2024-05-09 15:13 |DEBUG| org.springframework.security.oauth2.server.resource.authentication.JwtAuthenticationProvider.getJwt()
Failed to authenticate since the JWT was invalid
2024-05-09 15:13 |DEBUG| org.springframework.security.web.context.HttpSessionSecurityContextRepository.saveContext()
Did not store empty SecurityContext
2024-05-09 15:13 |DEBUG| org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter()
Cleared SecurityContextHolder to complete request

我尝试添加 AccessDeniedHandler 甚至将其与 AuthenticationEntryPoint 结合使用,但没有成功。另外,我尝试设置一个自定义过滤器,在引发异常时抛出异常,但这也不起作用。我希望能够自定义处理这些身份验证异常,并且不让 Spring Boot 处理它们。它所做的只是更改身份验证标头,但这不是我想要的,我想从 API 获得明确的响应。

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

我能够解决这个问题,将 AuthenticationEntryPoint 移动到 oauth2ResourceServer 中,这是 SecurityFilterChain 的新代码:

@Configuration
@EnableWebSecurity
public class SecurityConfig {
@Value("${cognito.issuer}")
private String jwkIssuerUri;

@Autowired
private JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint;

@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
    http
            .csrf().disable()
            .authorizeRequests(authorizeRequests ->
                    authorizeRequests
                            .antMatchers("/auth/callback").permitAll()
                            .anyRequest().authenticated()
            ).oauth2ResourceServer(oauth2ResourceServer ->
                    oauth2ResourceServer.jwt(jwt ->
                            jwt.decoder(jwtDecoder())
                    )
                    .authenticationEntryPoint(jwtAuthenticationEntryPoint)
            );
    return http.build();
}

@Bean
public JwtDecoder jwtDecoder() {
    return JwtDecoders.fromOidcIssuerLocation(jwkIssuerUri);
}

}

现在所有身份验证异常都由我的 AuthenticationEntryPoint 类进行处理

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