20

WebApplicationInitializer将 Spring Security 添加到使用 Spring 的新接口而不是 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 模式映射,如果有更好的方法,我不想更改所有内容的过滤器注册。

4

7 回答 7

27

这就是我这样做的方式:

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

容器是一个实例ServletContext

于 2013-01-07T22:42:44.407 回答
16

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 ...
}
于 2015-06-17T20:58:14.413 回答
8
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等添加映射...

于 2013-01-08T11:00:57.960 回答
3

经过一番努力,我发现它实际上很简单:

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 安全信息的引用。

因此,我的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>

RootConfig如果我将andWebAppConfig类合并为 justWebAppConfig并具有以下内容,我将无法使其工作:

@Override
protected Class< ? >[] getRootConfigClasses() {
    return null;
}

@Override
protected Class< ? >[] getServletConfigClasses() {
    return new Class[] { WebAppConfig.class };
}
于 2013-07-02T05:41:44.687 回答
2
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 等。

于 2015-07-09T16:20:34.400 回答
0

面临同样的问题。合并 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, "/*");
于 2014-03-18T22:59:15.093 回答
0

这与那些对具有安全性的 Spring Boot 感兴趣的人有关:您不需要任何东西,Spring Boot 拿起 @components 并解决其他问题

于 2017-12-15T12:40:11.037 回答