我有一个使用基本身份验证以Spring Security运行的Spring Boot应用程序。
提供正确的基本身份验证凭据后,一切都很好,但是对于不正确的身份验证凭据,spring会出现HttpRequestMethodNotSupportedException: Request method 'POST' not supported异常。

根据日志, Spring 已识别出身份验证失败,但事实并非如此。
2015-08-12 09:33:10.922 INFO 16988 --- [nio-8080-exec-4] o.s.b.a.audit.listener.AuditListener : AuditEvent [timestamp=Wed Aug 12 09:33:10 AEST 2015, principal=anonymousUser, type=AUTHORIZATION_FAILURE, data={type=org.springframework.security.access.AccessDeniedException, message=Access is denied}]2015-08-12 09:33:10.927 TRACE 16988 --- [nio-8080-exec-4] o.s.web.servlet.DispatcherServlet : Bound request context to thread: FirewalledRequest[ org.apache.catalina.core.ApplicationHttpRequest@483e1fc6]2015-08-12 09:33:10.927 DEBUG 16988 --- [nio-8080-exec-4] o.s.web.servlet.DispatcherServlet : DispatcherServlet with name 'dispatcherServlet' processing POST request for [/myapplication/error]2015-08-12 09:33:10.927 TRACE 16988 --- [nio-8080-exec-4] o.s.web.servlet.DispatcherServlet : Testing handler map [org.springframework.web.servlet.handler.SimpleUrlHandlerMapping@331bb032] in DispatcherServlet with name 'dispatcherServlet'2015-08-12 09:33:10.927 TRACE 16988 --- [nio-8080-exec-4] o.s.w.s.handler.SimpleUrlHandlerMapping : No handler mapping found for [/error]2015-08-12 09:33:10.927 TRACE 16988 --- [nio-8080-exec-4] o.s.web.servlet.DispatcherServlet : Testing handler map [org.springframework.boot.actuate.endpoint.mvc.EndpointHandlerMapping@69e79b9b] in DispatcherServlet with name 'dispatcherServlet'2015-08-12 09:33:10.927 TRACE 16988 --- [nio-8080-exec-4] o.s.web.servlet.DispatcherServlet : Testing handler map [org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping@27cc0354] in DispatcherServlet with name 'dispatcherServlet'2015-08-12 09:33:10.927 DEBUG 16988 --- [nio-8080-exec-4] s.w.s.m.m.a.RequestMappingHandlerMapping : Looking up handler method for path /error2015-08-12 09:33:10.928 DEBUG 16988 --- [nio-8080-exec-4] .m.m.a.ExceptionHandlerExceptionResolver : Resolving exception from handler [null]: org.springframework.web.HttpRequestMethodNotSupportedException: Request method 'POST' not supported
通过上面的日志和调试spring的源代码后,我发现,在识别出凭据不正确的情况下,spring创建了BadCredentials异常,然后尝试重定向到“/error”,这种重定向是导致HttpMethodNotAllowed异常的原因。应用程序没有/error端点)。

我试图通过配置以下内容来告诉spring不要使用/error,

`公共(public)类ServerCustomization扩展了ServerProperty {

@Override
public void customize(ConfigurableEmbeddedServletContainer container) {

    super.customize(container);
    container.addErrorPages(new ErrorPage(HttpStatus.UNAUTHORIZED, null));

}`

这将使spring停止吐出HttpMethodnotallowed异常,并使其带有401(Unauthorized),但该异常未被我的Exception处理程序捕获(使用@ControllerAdvice配置)。

我也尝试如下配置自定义身份验证入口点,但没有任何运气。
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {

AlwaysSendUnauthorized401AuthenticationEntryPoint alwaysSendUnauthorized401AuthenticationEntryPoint =
        new AlwaysSendUnauthorized401AuthenticationEntryPoint();


@Override
protected void configure(HttpSecurity http) throws Exception {
    http.headers().httpStrictTransportSecurity().xssProtection().and().authorizeRequests().anyRequest().fullyAuthenticated()
            .and().csrf().disable();

    http.exceptionHandling().authenticationEntryPoint(alwaysSendUnauthorized401AuthenticationEntryPoint);
}

public class AlwaysSendUnauthorized401AuthenticationEntryPoint implements AuthenticationEntryPoint {
    @Override
    public final void commence(HttpServletRequest request, HttpServletResponse response,
            AuthenticationException authException) throws IOException {
        response.sendError(HttpServletResponse.SC_UNAUTHORIZED);
    }
}

}

我们有什么方法可以指定不跳转到/error并返回Bad Credentials Exception?

最佳答案

我使用以下安全配置创建了一个示例Spring Boot应用程序:

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

    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication().withUser("test").password("password").roles("USER");
    }

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

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.headers().httpStrictTransportSecurity().xssProtection()
                .and().authorizeRequests().anyRequest().fullyAuthenticated()
                .and().csrf().disable();

        http.httpBasic().authenticationEntryPoint(authenticationEntryPoint());
        http.exceptionHandling().authenticationEntryPoint(authenticationEntryPoint());

    }
}

输入无效的用户名/密码(测试/密码以外的任何其他密码)时,我得到以下响应:
{"timestamp":1439381390204,"status":401,"error":"Unauthorized","message":"Bad credentials","path":"/"}

该错误由org.springframework.boot.autoconfigure.web.BasicErrorController类返回,如果您看一下,它确实使用@RequestMapping("/error")定义了两个方法-errorHtmlerror。由于您正在构建API,因此应该调用第二个API,我想这就是“正确”的行为!

因此,首先,请检查验证失败时是否进入BasicErrorController。如果是这样,请确保您正在使用error方法NOT errorHtml

如果以上方法均无效,请检查是否有人重写了错误 Controller 的默认行为。一种常见(有效)扩展是实现您自己的org.springframework.boot.autoconfigure.web.ErrorAttributes来更改默认错误有效负载。但是,用非标准实现替换整个BasicErrorController一样容易,因此请在您的应用程序中进行检查。

如果所有其他方法都失败了,并且您确定要禁用Spring的默认错误处理(我不建议这样做),请尝试将其添加到配置中:
@EnableAutoConfiguration(exclude = {ErrorMvcAutoConfiguration.class})
这将确保不会将错误 Controller 加载到应用程序上下文中。

10-07 15:36