Spring Security without web.xml

时光毁灭记忆、已成空白 提交于 2019-12-02 15:38:44

This is the way that I have done it:

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

container is an instance of ServletContext

The Spring Security Reference answers this question and the solution depends on whether or not you are using Spring Security in conjunction with Spring or Spring MVC.

Using Spring Security without Spring or Spring MVC

If you are not using Spring Security with Spring or Spring MVC (i.e. you do not have an existing WebApplicationInitializer) then you need to provide the following additional class:

import org.springframework.security.web.context.*;

public class SecurityWebApplicationInitializer
    extends AbstractSecurityWebApplicationInitializer {

    public SecurityWebApplicationInitializer() {
        super(SecurityConfig.class);
    }
}

Where SecurityConfig is your Spring Security Java configuration class.

Using Spring Security with Spring or Spring MVC

If you are using Spring Security with Spring or Spring MVC (i.e. you have an existing WebApplicationInitializer) then firstly you need to provide the following additional class:

import org.springframework.security.web.context.*;

public class SecurityWebApplicationInitializer
    extends AbstractSecurityWebApplicationInitializer {
}

Then you need to ensure that your Spring Security Java configuration class, SecurityConfig in this example, is declared in your existing Spring or Spring MVC WebApplicationInitializer. For example:

import org.springframework.web.servlet.support.*;

public class MvcWebApplicationInitializer
    extends AbstractAnnotationConfigDispatcherServletInitializer {

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

    // ... other overrides ...
}
Dynamic securityFilter = servletContext.addFilter(AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME, DelegatingFilterProxy.class);
securityFilter.addMappingForUrlPatterns(EnumSet.allOf(DispatcherType.class), false, "/*");

EnumSet.allOf(DispatcherType.class) to be sure that you add a mapping not only for default DispatcherType.REQUEST, but for DispatcherType.FORWARD, etc...

After a bit of work, I've discovered that it's actually quite simple:

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") };
    }
}

The most important thing, though, is that you must have a root context (e.g. RootConfig in this case), and that must contain a reference to all the spring security information.

Thus, my RootConfig class:

@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;
    }
}

And 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>

I could not get it to work if I merged the RootConfig and WebAppConfig classes into just WebAppConfig and had the following:

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

@Override
protected Class< ? >[] getServletConfigClasses() {
    return new Class[] { WebAppConfig.class };
}
Deepak
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, "/*");
    }

}

This scenario is for executing a filter before executing other filters. If you want to execute a filter after other filers pass true in registration.addMappingForUrlPatterns(EnumSet.of(DispatcherType.REQUEST), true, "/*");. Also check the DispatcherType ASYNC, FORWARD etc.

Faced with the same problem. Merge RootConfig and WebAppConfig - not best way - because this i did not try this solution. Tried all other solutions - everty time got "org.apache.catalina.core.StandardContext.startInternal Error filterStart". After some work, got something like this:

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

But is not working with DelegatingFilterProxy(). Continue finding for best common solution for all filters.

UPDATE: I did it.

So, the main issue is: if you want add filters using java config, especially if you want to add security filter, such as DelegatingFilterProxy, then you have to create WebAppSecurityConfig:

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

In this case i create WebAppSecurityConfig and make import resource ("security.xml"). This let me to do that in Initializer class:

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

This is related to those interested in Spring Boot with security: You don't need anything, Spring Boot picks up the @components and solves the other issues

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!