Spring Boot Security 不会抛出 401 Unauthorized Exception 但 404 Not Found

新手上路,请多包涵

我的身份验证基于 spring-boot-security-example 。当我输入无效令牌时,我想抛出 401 Unauthorized 异常。但是,我总是得到 404 找不到资源。我的配置设置了一个异常处理,但它被忽略了——可能是因为我的 AuthenticationFilter 是之前添加的,并且请求没有到达我的异常处理程序。

我需要更改什么才能抛出 401 异常?

我有一个身份验证过滤器:

 public class AuthenticationFilter extends GenericFilterBean {

...

@Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
    HttpServletRequest httpRequest = asHttp(request);
    HttpServletResponse httpResponse = asHttp(response);
    Optional<String> token = Optional.fromNullable(httpRequest.getHeader("X-Auth-Token"));

    try {
        if (token.isPresent()) {
            logger.debug("Trying to authenticate user by X-Auth-Token method. Token: {}", token);
            processTokenAuthentication(token);
            addSessionContextToLogging();
        }

        logger.debug("AuthenticationFilter is passing request down the filter chain");
        chain.doFilter(request, response);
    } catch (InternalAuthenticationServiceException internalAuthenticationServiceException) {
        SecurityContextHolder.clearContext();
        logger.error("Internal authentication service exception", internalAuthenticationServiceException);
        httpResponse.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
    } catch (AuthenticationException authenticationException) {
        SecurityContextHolder.clearContext();
        httpResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED, authenticationException.getMessage());
    } finally {
        MDC.remove(TOKEN_SESSION_KEY);
        MDC.remove(USER_SESSION_KEY);
    }
}

private void addSessionContextToLogging() {
    ...
}

...

private void processTokenAuthentication(Optional<String> token) {
    Authentication resultOfAuthentication = tryToAuthenticateWithToken(token);
    SecurityContextHolder.getContext().setAuthentication(resultOfAuthentication);
}

private Authentication tryToAuthenticateWithToken(Optional<String> token) {
    PreAuthenticatedAuthenticationToken requestAuthentication = new PreAuthenticatedAuthenticationToken(token, null);
    return tryToAuthenticate(requestAuthentication);
}

private Authentication tryToAuthenticate(Authentication requestAuthentication) {
    Authentication responseAuthentication = authenticationManager.authenticate(requestAuthentication);
    if (responseAuthentication == null || !responseAuthentication.isAuthenticated()) {
        throw new InternalAuthenticationServiceException("Unable to authenticate Domain User for provided credentials");
    }
    logger.debug("User successfully authenticated");
    return responseAuthentication;
}

AuthenticationProvider 实现:

 @Provider
public class TokenAuthenticationProvider implements AuthenticationProvider {

@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
    Optional<String> token = (Optional) authentication.getPrincipal();
    if (!token.isPresent() || token.get().isEmpty()) {
        throw new BadCredentialsException("No token set.");
    }
    if (!myCheckHere()){
        throw new BadCredentialsException("Invalid token");
    }

    return new PreAuthenticatedAuthenticationToken(myConsumerObject, null, AuthorityUtils.commaSeparatedStringToAuthorityList("ROLE_API_USER"));
}

...

}

以及如下所示的配置:

 @Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

@Override
protected void configure(HttpSecurity http) throws Exception {
    http.
            csrf().disable().
            sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).
            and().
            anonymous().disable().
            exceptionHandling().authenticationEntryPoint(unauthorizedEntryPoint());

    http.addFilterBefore(new AuthenticationFilter(authenticationManager()), BasicAuthenticationFilter.class);
}

@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
    auth.authenticationProvider(tokenAuthenticationProvider());
}

@Bean
public AuthenticationProvider tokenAuthenticationProvider() {
    return new TokenAuthenticationProvider();
}

@Bean
public AuthenticationEntryPoint unauthorizedEntryPoint() {
    return (request, response, authException) -> response.sendError(HttpServletResponse.SC_UNAUTHORIZED);
}
}

原文由 Frame91 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 1.6k
2 个回答

我在这个线程中找到了答案: Return HTTP Error 401 Code & Skip Filter Chains

代替

httpResponse.sendError(HttpServletResponse.SC_UNAUTHORIZED, authenticationException.getMessage());

我需要打电话

httpResponse.setStatus(HttpServletResponse.SC_UNAUTHORIZED);

当我不继续调用它并将状态设置为不同的代码时,链条似乎会停止 - 异常被正确抛出

原文由 Frame91 发布,翻译遵循 CC BY-SA 3.0 许可协议

我通过在我的顶级 @SpringBootApplication 类上添加以下注释来解决它:

 @EnableAutoConfiguration(exclude = {ErrorMvcAutoConfiguration.class})

Spring Boot 会不会找不到它的默认错误页面?

原文由 candide 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题