Quelle est la méthode recommandée pour ajouter Spring Security à une application Web qui utilise la nouvelle interface WebApplicationInitializer
de Spring au lieu du fichier web.xml? Je cherche l'équivalent de:
<filter>
<filter-name>springSecurityFilterChain</filter-name>
<filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>
</filter>
METTRE &AGRAVE; JOUR
Les réponses fournies sont raisonnables, mais elles supposent toutes les deux que j'ai une instance servletContext
. J'ai parcouru la hiérarchie de WebApplicationInitializer
s et je ne vois aucun accès au contexte de servlet à moins que je ne décide de remplacer l'une des méthodes d'initialisation de Spring. AbstractDispatcherServletInitializer.registerServletFilter
semble être le choix judicieux, mais il ne s'agit pas du mappage de modèle d'URL par défaut et je ne voudrais pas modifier l'enregistrement du filtre pour tout s'il existe un meilleur moyen.
C'est comme ça que je l'ai fait:
container.addFilter("springSecurityFilterChain", new DelegatingFilterProxy("springSecurityFilterChain"))
.addMappingForUrlPatterns(null, false, "/*");
conteneur est une instance de ServletContext
La référence Spring Security répond à cette question et la solution dépend si vous utilisez ou non Spring Security avec Spring ou Spring MVC.
Si vous utilisez not avec Spring Security avec Spring ou Spring MVC (c.-à-d. Que vous n'avez pas de WebApplicationInitializer
existante), vous devez fournir la classe supplémentaire suivante:
import org.springframework.security.web.context.*;
public class SecurityWebApplicationInitializer
extends AbstractSecurityWebApplicationInitializer {
public SecurityWebApplicationInitializer() {
super(SecurityConfig.class);
}
}
Où SecurityConfig
est votre classe de configuration Spring Security Java.
Si vous utilisez Spring Security avec Spring ou Spring MVC (c’est-à-dire que vous avez une WebApplicationInitializer
existante), vous devez d’abord fournir la classe supplémentaire suivante:
import org.springframework.security.web.context.*;
public class SecurityWebApplicationInitializer
extends AbstractSecurityWebApplicationInitializer {
}
Ensuite, vous devez vous assurer que votre classe de configuration Spring Security Java, SecurityConfig
dans cet exemple, est déclarée dans votre Spring ou Spring MVC existant WebApplicationInitializer
. Par exemple:
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) pour vous assurer d'ajouter un mappage non seulement pour DispatcherType.REQUEST par défaut, mais également pour DispatcherType.FORWARD , etc ...
Après un peu de travail, j'ai découvert que c'était en fait assez 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") };
}
}
La chose la plus importante, cependant, est que vous devez avoir un contexte racine (par exemple, RootConfig
dans ce cas) et qu’il contienne une référence à toutes les informations de sécurité de Spring.
Ainsi, ma classe 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;
}
}
Et 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>
Je ne pouvais pas le faire fonctionner si je fusionnais les classes RootConfig
et WebAppConfig
dans juste WebAppConfig
et que j'avais les caractéristiques suivantes:
@Override
protected Class< ? >[] getRootConfigClasses() {
return null;
}
@Override
protected Class< ? >[] getServletConfigClasses() {
return new Class[] { WebAppConfig.class };
}
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, "/*");
}
}
Ce scénario permet d’exécuter un filtre avant d’exécuter d’autres filtres. Si vous souhaitez exécuter un filtre après que d’autres fichiers aient passé true
dans registration.addMappingForUrlPatterns(EnumSet.of(DispatcherType.REQUEST), true, "/*");
. Vérifiez également le DispatcherType ASYNC, FORWARD, etc.
Ceci est lié à ceux qui s'intéressent à Spring Boot avec sécurité: vous n'avez besoin de rien, Spring Boot récupère les composants @ et résout les autres problèmes
Face au même problème. Fusionner RootConfig et WebAppConfig - pas le meilleur moyen - parce que je n'ai pas essayé cette solution. Essayé toutes les autres solutions - everty time got "org.Apache.catalina.core.StandardContext.startInternal Error filterStart". Après quelques travaux, j'ai obtenu quelque chose comme ça:
FilterRegistration.Dynamic enc= servletContext.addFilter("encodingFilter",
new CharacterEncodingFilter());
encodingFilter .setInitParameter("encoding", "UTF-8");
encodingFilter .setInitParameter("forceEncoding", "true");
encodingFilter .addMappingForUrlPatterns(null, true, "/*");
Mais ne fonctionne pas avec DelegatingFilterProxy (). Continuez à rechercher la meilleure solution commune pour tous les filtres.
UPDATE: Je l'ai fait.
Le problème principal est donc le suivant: si vous souhaitez ajouter des filtres à l'aide de la configuration Java, en particulier si vous souhaitez ajouter un filtre de sécurité, tel que DelegatingFilterProxy, vous devez créer WebAppSecurityConfig:
@Configuration
@EnableWebSecurity
@ImportResource("classpath:security.xml")
public class WebAppSecurityConfig extends WebSecurityConfigurerAdapter {
}
Dans ce cas, je crée WebAppSecurityConfig et crée une ressource d'importation ("security.xml"). Ceci me permet de le faire dans la classe Initializer:
servletContext.addFilter("securityFilter", new DelegatingFilterProxy("springSecurityFilterChain"))
.addMappingForUrlPatterns(null, false, "/*");