【问题标题】:Tomcat 7 and AbstractSecurityWebApplicationInitializer are not working togetherTomcat 7 和 AbstractSecurityWebApplicationInitializer 不能一起工作
【发布时间】:2013-07-11 19:36:18
【问题描述】:

我正在关注这个article 来尝试一个基本的 http-auth 而不使用 web.xml

我使用的是 Tomcat 7.0.41,这些是我对 gradle 的依赖:

  ext.springVersion =  "3.2.1.RELEASE"
  compile "org.springframework:spring-jdbc:$springVersion",
          "org.springframework:spring-context:$springVersion",
          "org.springframework:spring-web:$springVersion",
          "org.springframework:spring-webmvc:$springVersion",
          "org.springframework.security:spring-security-core:3.2.0.M2",
          "org.springframework.security:spring-security-web:3.2.0.M2",
          "org.springframework.security:spring-security-config:3.2.0.M2",

根据教程我定义了以下

@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

    @Override
    protected void registerAuthentication(AuthenticationManagerBuilder auth)
            throws Exception {
        auth.inMemoryAuthentication().withUser("admin").password("admin")
                .roles("USER");
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.authorizeUrls().antMatchers("/").hasRole("USER")
                .and().httpBasic();
    }

}

然后像这样将该类添加到初始化程序中:

@Order(1)
public class ServletConfiguration extends
        AbstractAnnotationConfigDispatcherServletInitializer {

    @Override
    protected Class<?>[] getRootConfigClasses() {
        return new Class[] { SecurityConfiguration.class };
        // return null;
    }

    @Override
    protected Class<?>[] getServletConfigClasses() {
        return new Class[] { AppConfiguration.class };
    }

    @Override
    protected String[] getServletMappings() {
        return new String[] { "/" };
    }

//  @Override
//  protected Dynamic registerServletFilter(ServletContext servletContext,
//          Filter filter) {
//      Dynamic securityFilter = servletContext.addFilter(
//              "springSecurityFilterChain", DelegatingFilterProxy.class);
//      securityFilter.addMappingForUrlPatterns(
//              EnumSet.allOf(DispatcherType.class), false, "/*");
//      return securityFilter;
//  }

}

最后添加了一个类来初始化springSecurityFilterChain:

@Order(2)
public class SecurityInitializer extends AbstractSecurityWebApplicationInitializer  {
@Override
protected void afterSpringSecurityFilterChain(ServletContext servletContext) {
    System.out.println("afterSpringSecurityFilterChain");
    super.afterSpringSecurityFilterChain(servletContext);
}
}

但我总是收到此错误:

DEBUG: org.springframework.jndi.JndiPropertySource - JNDI lookup for name [spring.liveBeansView.mbeanDomain] threw NamingException with message: Name [spring.liveBeansView.mbeanDomain] is not bound in this Context. Unable to find [spring.liveBeansView.mbeanDomain].. Returning null.
Jul 11, 2013 9:22:24 PM org.apache.catalina.core.StandardContext filterStart
SEVERE: Exception starting filter springSecurityFilterChain
org.springframework.beans.factory.NoSuchBeanDefinitionException: No bean named 'springSecurityFilterChain' is defined

我不知道为什么,因为当我调试服务器初始化时,实际上调用了这两个方法:

@Override
public final void onStartup(ServletContext servletContext)
        throws ServletException {
    if(enableHttpSessionEventPublisher()) {
        servletContext.addListener(HttpSessionEventPublisher.class);
    }
    insertSpringSecurityFilterChain(servletContext);
    afterSpringSecurityFilterChain(servletContext);
}

然后

private void insertSpringSecurityFilterChain(ServletContext servletContext) {
    String filterName = "springSecurityFilterChain";
    DelegatingFilterProxy springSecurityFilterChain = new DelegatingFilterProxy(filterName);
    String contextAttribute = getWebApplicationContextAttribute();
    if(contextAttribute != null) {
        springSecurityFilterChain.setContextAttribute(contextAttribute);
    }
    registerFilter(servletContext, true, filterName, springSecurityFilterChain);
}

所以实际上过滤器被创建了。但后来它迷路了。

我尝试使用@Order,但那无济于事,因此我尝试使用registerServletFilter 方法注册springSecurityFilterChain,但我没有获得任何http-auth 请求身份验证。 而且SecurityConfiguration 甚至都没有加载。

【问题讨论】:

    标签: java spring-security tomcat7 servlet-3.0


    【解决方案1】:

    SecurityInitializer 创建 DelegatingFilterProxy,用于通过 springSecurityFilterChain 的名称查找 bean。 springSecurityFilterChain 是使用@EnableWebSecurity 创建的。问题是您缺少 @Configuration 注释(没有它,Root ApplicationContext 甚至不会尝试加载 SecurityConfiguration)。具体来说,您要执行以下操作:

    @Configuration
    @EnableWebSecurity
    public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
    ...
    }
    

    还有几点需要指出:

    • 您不需要使用@Order,因为您没有添加任何其他过滤器
    • 您保护的唯一 URL 是上下文根(即 /)。
    • 您需要注意need spring security java config example showing basic auth only 上讨论的 httpBasic() 错误
    • 更新:我还应该指出我已经记录了SPR-10660 以支持@Enable* 注释,而没有@Configuration。解决之后,您的问题就会神奇地消失。

    【讨论】:

    • 非常感谢!我读了更多次。尽管这个问题有助于了解该错误。再次感谢!
    • 没问题@dierre :) 请注意,我添加了一个更新,引用了另一个 JIRA,一旦解决,它就会为您解决此问题。
    • 我看到 SPR-10660 在 2.5 年后仍未解决。
    • @DerekMahar 这实际上已作为另一个问题解决(请参阅问题更新)。你试过 Spring 4.0+ 吗?
    • 不,我没有在 Spring 4.0+ 上尝试过这个。其实我从来没有遇到过这个问题!我只是在寻找另一个问题的解决方案时路过,其中 Spring MVC 和安全应用程序两次实例化相同的 bean。我通过更好地理解 @ComponentScan 的工作原理以及 Spring MVC 中根上下文和调度程序上下文之间的关系,找到了解决此问题的方法。与这里的问题无关。无论如何,感谢您解决 SPR-10660。
    猜你喜欢
    • 2015-04-22
    • 1970-01-01
    • 2011-12-24
    • 2020-11-20
    • 1970-01-01
    • 1970-01-01
    • 2019-06-21
    • 2023-03-26
    • 1970-01-01
    相关资源
    最近更新 更多