Spring安全性,基本身份验证重定向到无效凭据/错误

Spring安全性,基本身份验证重定向到无效凭据/错误,spring,security,authentication,basic-authentication,credentials,Spring,Security,Authentication,Basic Authentication,Credentials,我有一个SpringBoot应用程序,它使用基本身份验证运行SpringSecurity。 当提供了正确的基本身份验证凭据时,一切正常,但对于不正确的身份验证凭据,spring会出现一个HttpRequestMethodNotSupportedException:RequestMethod'POST'不受支持的异常 根据日志,spring已经识别出身份验证失败,但结果并非如此 2015-08-12 09:33:10.922信息16988-[nio-8080-exec-4]o.s.b.a.audi

我有一个SpringBoot应用程序,它使用基本身份验证运行SpringSecurity。 当提供了正确的基本身份验证凭据时,一切正常,但对于不正确的身份验证凭据,spring会出现一个
HttpRequestMethodNotSupportedException:RequestMethod'POST'不受支持的
异常

根据日志,spring已经识别出身份验证失败,但结果并非如此

2015-08-12 09:33:10.922信息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\u FAILURE,data={type=org.springframework.security.access.AccessDeniedException,message=access被拒绝访问}]
2015-08-12 09:33:10.927 TRACE 16988---[nio-8080-exec-4]o.s.web.servlet.DispatcherServlet:将请求上下文绑定到线程:FirewalledRequest[org.apache.catalina.core。ApplicationHttpRequest@483e1fc6]
2015-08-12 09:33:10.927调试16988---[nio-8080-exec-4]o.s.web.servlet.DispatcherServlet:DispatcherServlet,名称为“DispatcherServlet”处理[/myapplication/error]的POST请求
2015-08-12 09:33:10.927 TRACE 16988---[nio-8080-exec-4]o.s.web.servlet.DispatcherServlet:测试处理程序映射[org.springframework.web.servlet.handler。SimpleUrlHandlerMapping@331bb032]在名为“DispatcherServlet”的DispatcherServlet中
2015-08-12 09:33:10.927跟踪16988---[nio-8080-exec-4]o.s.w.s.handler.SimpleUrlHandlerMapping:未找到[/error]的处理程序映射
2015-08-12 09:33:10.927 TRACE 16988---[nio-8080-exec-4]o.s.web.servlet.DispatcherServlet:测试处理程序映射[org.springframework.boot.actuate.endpoint.mvc。EndpointHandlerMapping@69e79b9b]在名为“DispatcherServlet”的DispatcherServlet中
2015-08-12 09:33:10.927 TRACE 16988---[nio-8080-exec-4]o.s.web.servlet.DispatcherServlet:测试处理程序映射[org.springframework.web.servlet.mvc.method.annotation]。RequestMappingHandlerMapping@27cc0354]在名为“DispatcherServlet”的DispatcherServlet中
2015-08-12 09:33:10.927调试16988---[nio-8080-exec-4]s.w.s.m.m.a.RequestMappingHandlerMapping:查找路径/错误的处理程序方法
2015-08-12 09:33:10.928调试16988---[nio-8080-exec-4].m.a.ExceptionHandlerExceptionResolver:从处理程序解析异常[null]:org.springframework.web.HttpRequestMethodNotSupportedException:不支持请求方法“POST”

通过以上日志&在调试spring源代码之后,我发现在识别出凭据不正确后,spring创建了一个BadCredentials异常,然后尝试重定向到“/error”,这个重定向就是导致HttpMethodNotAllowed异常的原因。(我的应用程序没有/error端点)

我试图通过配置以下命令来告诉spring不要使用/error

`公共类ServerCustomization扩展了ServerProperties{

@Override
public void customize(ConfigurableEmbeddedServletContainer container) {

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

}`
这将使spring停止抛出HttpMethodnotallowed异常,并生成401(未经授权),但我的异常处理程序(使用
@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);
    }
}
}


我们是否可以指定spring不重定向到/error并返回错误凭据异常?

我认为应该使用
http.exceptionHandling().authenticationEntryPoint
而不是
http.httpBasic().authenticationEntryPoint
。对于基于表单的身份验证,这适用于我:

http
    .formLogin()
        .failureHandler(authenticationFailureHandler())
        ...
    ...
对于身份验证失败处理程序,可以使用Spring的
SimpleRuthenticationFailureHandler
。在没有任何参数的情况下实例化时,它将执行我们想要的操作:

@Bean
public AuthenticationFailureHandler authenticationFailureHandler() {
    return new SimpleUrlAuthenticationFailureHandler();
}   

是我的完整安全配置文件,以防有用。

我创建了一个示例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”)
-
errorHtml
error
定义了两个方法。因为您正在构建一个API,所以应该调用第二个API,我认为这是“正确”的行为

因此,首先,检查身份验证失败时您是否正在访问
BasicErrorController
。如果是,请确保所点击的是
error
方法,而不是
errorHtml

如果以上任何一项都没有帮助,请检查是否有人覆盖了错误控制器的默认行为。一个常见的(也是有效的)扩展是实现您自己的
org.springframework.boot.autoconfigure.web.ErrorAttributes
,以更改默认的错误负载。但是用非标准实现替换整个
BasicErrorController
也同样容易,所以请在应用程序中检查这一点

如果所有其他操作都失败,并且您坚持要禁用Spring的默认错误处理(我不建议这样做),请尝试将以下内容添加到您的配置中:

@EnableAutoConfiguration(exclude={ErrorMvcAutoConfiguration.class})


这将确保错误控制器不会加载到应用程序上下文中。

Thank@Sanjay,稍后将尝试一下,并让您知道它是如何尝试两种解决方案的,但还没有成功。
formLogin()
看起来不正确,因为我的是restrul API。关于
authenticationEntryPoint
的另一个建议看起来很有希望,但没有产生任何效果。感谢@grigori为我指明了正确的方向。确实存在BasicErrorController的非标准实现