从Spring Boot中的Basic身份验证中删除WWW-authenticate头

时间:2015-12-15 17:56:56

标签: java spring authentication spring-security spring-boot

我正在使用SpringBoot设计REST API。与此同时,我正在构建一个使用该API的SPA。

为了安全起见,我选择了Basic Auth,它很容易设置。我现在面临401挑战问题。当我的SPA向我的API发出请求时,如果auth失败,浏览器会显示我想要删除的经典登录弹出窗口。

我看了herethere,当401响应中还包含值为' Basic'的基本身份验证的WWW-authenticate标头时,浏览器会显示此弹出窗口。

所以要删除它,根据Spring Security,我将提供自己的AuthenticationEntryPoint。 Spring Boot默认情况下有点像it's done。我试过这个,但它不起作用,我在运行时得到一个堆栈。有什么想法吗?

这是我的代码

@Order(SecurityProperties.BASIC_AUTH_ORDER)
@Configuration
public class CustomWebSecurityConfigurerAdapter extends  WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {

       AuthenticationEntryPoint entryPoint = new CustomAuthenticationEntryPoint();

        http
            .sessionManagement()
                .sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
            .authorizeRequests()
            .regexMatchers("/api/.*").authenticated().and()
            .httpBasic().authenticationEntryPoint(entryPoint).and()
            .exceptionHandling().authenticationEntryPoint(entryPoint).and()
            .csrf().disable();

     }
}

这是我使用mvn spring-boot:run

运行时获得的堆栈
java.lang.reflect.InvocationTargetException
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:497)
    at org.springframework.boot.maven.AbstractRunMojo$LaunchRunner.run(AbstractRunMojo.java:467)
    at java.lang.Thread.run(Thread.java:745)

Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'springSecurityFilterChain' defined in class path resource [org/springframework/security/config/annotation/web/configuration/WebSecurityConfiguration.class]: Bean instantiation via factory method failed; nested exception is org.springframework.beans.BeanInstantiationException: Failed to instantiate [javax.servlet.Filter]: Factory method 'springSecurityFilterChain' threw exception; nested exception is org.springframework.security.config.annotation.AlreadyBuiltException: This object has already been built
    at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:599)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1123)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:1018)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:510)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:482)
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:296)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:772)
    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:838)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:537)
    at org.springframework.boot.context.embedded.EmbeddedWebApplicationContext.refresh(EmbeddedWebApplicationContext.java:118)
    at org.springframework.boot.SpringApplication.refresh(SpringApplication.java:752)
    at org.springframework.boot.SpringApplication.doRun(SpringApplication.java:347)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:295)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1112)
    at org.springframework.boot.SpringApplication.run(SpringApplication.java:1101)
    at org.htulipe.WishlistApplication.main(WishlistApplication.java:44)
... 6 more

Caused by: org.springframework.beans.BeanInstantiationException: Failed to instantiate [javax.servlet.Filter]: Factory method 'springSecurityFilterChain' threw exception; nested exception is org.springframework.security.config.annotation.AlreadyBuiltException: This object has already been built
    at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:189)
    at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:588)
... 26 more

Caused by: org.springframework.security.config.annotation.AlreadyBuiltException: This object has already been built
at org.springframework.security.config.annotation.AbstractSecurityBuilder.build(AbstractSecurityBuilder.java:44)
at org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration.springSecurityFilterChain(WebSecurityConfiguration.java:105)
at org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration$$EnhancerBySpringCGLIB$$7d149fcb.CGLIB$springSecurityFilterChain$6(<generated>)
at org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration$$EnhancerBySpringCGLIB$$7d149fcb$$FastClassBySpringCGLIB$$208d4287.invoke(<generated>)
at org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:228)
at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:318)
at org.springframework.security.config.annotation.web.configuration.WebSecurityConfiguration$$EnhancerBySpringCGLIB$$7d149fcb.springSecurityFilterChain(<generated>)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:162)
... 27 more

3 个答案:

答案 0 :(得分:5)

有一个更简单的选择。只需将Http401AuthenticationEntryPoint添加到您的httpSecurity。

http.exceptionHandling()
    .authenticationEntryPoint(new Http401AuthenticationEntryPoint("FormBased"));

答案 1 :(得分:3)

发现问题,我在问题发布之前发送了另一个堆栈。堆栈抱怨我的AuthenticationEntryPoint缺少一个Realm名称。这里的记录是一个有效的例子:

public class CustomAuthenticationEntryPoint extends BasicAuthenticationEntryPoint{

    public CustomAuthenticationEntryPoint() {
        this.setRealmName("Yolo");
    }

    @Override
    public void commence(HttpServletRequest request, HttpServletResponse response, AuthenticationException authException)
        throws IOException, ServletException {
        response.setHeader("WWW-Authenticate", "FormBased");
        response.sendError(HttpServletResponse.SC_UNAUTHORIZED, authException.getMessage());
    }
}

答案 2 :(得分:1)

如果有人遇到类似的问题/挑战,我会张贴此内容。

在下面显示的AuthenticationServerConfigurerAdapter类中允许表单身份验证:

 @Override
public void configure(AuthorizationServerSecurityConfigurer oauthServer) throws Exception {
    oauthServer.checkTokenAccess("isAuthenticated()")
    .allowFormAuthenticationForClients();
}

这将允许您在表单中发送client_id和client_secret。另外,请确保您的表单已提交content-type:application/x-www-form-urlencoded标题。