【问题标题】:Spring Security without web.xml没有 web.xml 的 Spring Security
【发布时间】:2020-01-29 00:57:09
【问题描述】:

将 Spring Security 添加到使用 Spring 的新 WebApplicationInitializer 接口而不是 web.xml 文件的 Web 应用程序的推荐方法是什么?我正在寻找相当于:

<filter>
    <filter-name>springSecurityFilterChain</filter-name>
    <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>

更新
提供的答案是合理的,但他们都假设我有一个 servletContext 实例。我查看了WebApplicationInitializers 的层次结构,除非我选择重写 Spring 的初始化方法之一,否则我看不到任何对 servlet 上下文的访问。 AbstractDispatcherServletInitializer.registerServletFilter 似乎是明智的选择,但它并不默认为 URL 模式映射,如果有更好的方法,我不想更改所有内容的过滤器注册。

【问题讨论】:

  • 当您创建实现 WebApplicationInitializer 的类时,您将使用之前在 web.xml 中的内容覆盖“void onStartup(ServletContext servletContext)”。 ServletContext 将被传递给您的 WebApplicationInitializer 实现。

标签: spring-mvc spring-security servlet-3.0


【解决方案1】:

这就是我的做法:

container.addFilter("springSecurityFilterChain", new DelegatingFilterProxy("springSecurityFilterChain"))
                    .addMappingForUrlPatterns(null, false, "/*");

容器是ServletContext的一个实例

【讨论】:

    【解决方案2】:

    Spring Security Reference 回答了这个问题,解决方案取决于您是否将 Spring Security 与 Spring 或 Spring MVC 结合使用。

    在没有 Spring 或 Spring MVC 的情况下使用 Spring Security

    如果您将 Spring Security 与 Spring 或 Spring MVC 一起使用(即您没有现有的 WebApplicationInitializer),那么您需要提供以下附加类:

    import org.springframework.security.web.context.*;
    
    public class SecurityWebApplicationInitializer
        extends AbstractSecurityWebApplicationInitializer {
    
        public SecurityWebApplicationInitializer() {
            super(SecurityConfig.class);
        }
    }
    

    SecurityConfig 是您的 Spring Security Java 配置类。

    将 Spring Security 与 Spring 或 Spring MVC 一起使用

    如果您将 Spring Security 与 Spring 或 Spring MVC 一起使用(即您有一个现有的 WebApplicationInitializer),那么首先您需要提供以下附加类:

    import org.springframework.security.web.context.*;
    
    public class SecurityWebApplicationInitializer
        extends AbstractSecurityWebApplicationInitializer {
    }
    

    然后你需要确保你的 Spring Security Java 配置类,在这个例子中是 SecurityConfig,在你现有的 Spring 或 Spring MVC WebApplicationInitializer 中声明。例如:

    import org.springframework.web.servlet.support.*;
    
    public class MvcWebApplicationInitializer
        extends AbstractAnnotationConfigDispatcherServletInitializer {
    
        @Override
        protected Class<?>[] getRootConfigClasses() {
            return new Class[] {SecurityConfig.class};
        }
    
        // ... other overrides ...
    }
    

    【讨论】:

      【解决方案3】:
      Dynamic securityFilter = servletContext.addFilter(AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME, DelegatingFilterProxy.class);
      securityFilter.addMappingForUrlPatterns(EnumSet.allOf(DispatcherType.class), false, "/*");
      

      EnumSet.allOf(DispatcherType.class) 以确保您不仅为默认 DispatcherType.REQUEST 添加映射,还为 DispatcherType.FORWARD 等添加映射。 .

      【讨论】:

      • 为了独立于过滤器链的名称,使用AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME而不是springSecurityFilterChain似乎更合适。
      • 不错。谢谢你,@Koraktor
      【解决方案4】:

      经过一番努力,我发现其实很简单:

      public class Initialiser extends AbstractAnnotationConfigDispatcherServletInitializer implements WebApplicationInitializer {
      
          @Override
          protected Class< ? >[] getRootConfigClasses() {
              return new Class[] { RootConfig.class };
          }
      
          @Override
          protected Class< ? >[] getServletConfigClasses() {
              return new Class[] { WebAppConfig.class };
          }
      
          @Override
          protected String[] getServletMappings() {
              return new String[] { "/" };
          }
      
          @Override
          protected Filter[] getServletFilters() {
              return new Filter[] { new DelegatingFilterProxy("springSecurityFilterChain") };
          }
      }
      

      不过,最重要的是您必须有一个根上下文(例如,在这种情况下为 RootConfig),并且必须包含对所有 spring 安全信息的引用。 p>

      因此,我的RootConfig 班级:

      @ImportResource("classpath:spring/securityContext.xml")
      @ComponentScan({ "com.example.authentication", "com.example.config" })
      @Configuration
      public class RootConfig {
      
          @Bean
          public DatabaseService databaseService() {
              return new DefaultDatabaseService();
          }
      
          @Bean
          public ExceptionMappingAuthenticationFailureHandler authExceptionMapping() {
              final ExceptionMappingAuthenticationFailureHandler emafh = new ExceptionMappingAuthenticationFailureHandler();
              emafh.setDefaultFailureUrl("/loginFailed");
              final Map<String, String> mappings = new HashMap<>();
              mappings.put(CredentialsExpiredException.class.getCanonicalName(), "/change_password");
              emafh.setExceptionMappings(mappings);
              return emafh;
          }
      }
      

      还有spring/securityContext.xml

      <?xml version="1.0" encoding="UTF-8"?>
      <beans  xmlns="http://www.springframework.org/schema/beans"
              xmlns:security="http://www.springframework.org/schema/security"
              xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
              xmlns:context="http://www.springframework.org/schema/context"
              xsi:noNamespaceSchemaLocation="http://www.springframework.org/schema/beans/spring-beans-3.0.xsd"
              xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
                  http://www.springframework.org/schema/security http://www.springframework.org/schema/security/spring-security-3.1.xsd
                  http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd">
      
          <security:http security="none" pattern="/favicon.ico"/>
      
          <!-- Secured pages -->
          <security:http use-expressions="true">
              <security:intercept-url pattern="/login" access="permitAll" />
              <security:intercept-url pattern="/**" access="isAuthenticated()" />
              <security:form-login default-target-url="/index" login-processing-url="/login_form" login-page="/login" authentication-failure-handler-ref="authExceptionMapping" />
          </security:http>
      
          <security:authentication-manager>
              <security:authentication-provider ref="customAuthProvider" />
          </security:authentication-manager>
      </beans>
      

      如果我将 RootConfigWebAppConfig 类合并到 WebAppConfig 并具有以下内容,我无法让它工作:

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

      【讨论】:

        【解决方案5】:
        public class SIServerSecurityWebApplicationInitializer extends AbstractSecurityWebApplicationInitializer {
        
            @Override
            protected void beforeSpringSecurityFilterChain(ServletContext servletContext) {
                Dynamic registration = servletContext.addFilter("TenantServletFilter", TenantServletFilter.class);
                EnumSet<DispatcherType> dispatcherTypes = getSecurityDispatcherTypes();
                registration.addMappingForUrlPatterns(EnumSet.of(DispatcherType.REQUEST), false, "/*");
            }
        
        }
        

        此方案用于在执行其他过滤器之前执行过滤器。 如果您想在其他文件管理器通过trueregistration.addMappingForUrlPatterns(EnumSet.of(DispatcherType.REQUEST), true, "/*"); 之后执行过滤器。还要检查 DispatcherType ASYNC、FORWARD 等。

        【讨论】:

          【解决方案6】:

          面临同样的问题。合并 RootConfig 和 WebAppConfig - 不是最好的方法 - 因为我没有尝试这个解决方案。尝试了所有其他解决方案 - 每次都得到“org.apache.catalina.core.StandardContext.startInternal Error filterStart”。经过一番工作,得到了这样的东西:

              FilterRegistration.Dynamic enc= servletContext.addFilter("encodingFilter",
                      new CharacterEncodingFilter());
              encodingFilter .setInitParameter("encoding", "UTF-8");
              encodingFilter .setInitParameter("forceEncoding", "true");
              encodingFilter .addMappingForUrlPatterns(null, true, "/*");
          

          但不适用于 DelegatingFilterProxy()。继续为所有过滤器寻找最佳通用解决方案。

          更新: 我做到了。

          所以,主要问题是:如果你想使用 java config 添加过滤器,特别是如果你想添加安全过滤器,例如 DelegatingFilterProxy,那么你必须创建 WebAppSecurityConfig:

          @Configuration
          @EnableWebSecurity
          @ImportResource("classpath:security.xml")
          public class WebAppSecurityConfig extends WebSecurityConfigurerAdapter {
          }
          

          在这种情况下,我创建 WebAppSecurityConfig 并导入资源(“security.xml”)。 这让我可以在 Initializer 类中做到这一点:

          servletContext.addFilter("securityFilter", new DelegatingFilterProxy("springSecurityFilterChain"))
                      .addMappingForUrlPatterns(null, false, "/*");
          

          【讨论】:

            【解决方案7】:

            这和那些对安全的Spring Boot感兴趣的人有关:你什么都不需要,Spring Boot拿起@components并解决其他问题

            【讨论】:

              猜你喜欢
              • 1970-01-01
              • 1970-01-01
              • 2013-09-18
              • 2011-05-16
              • 2022-06-13
              • 2016-03-19
              • 2016-04-24
              • 2021-01-16
              • 2015-07-10
              相关资源
              最近更新 更多