Je suis nouveau au printemps alors je bricole avec des problèmes de sécurité ..__ À chaque fois que je lance mon application, je reçois:
org.springframework.beans.factory.BeanCreationException: Erreur lors de la création d'un bean avec le nom 'securityConfig': L'injection de dépendances autowired a échoué; L'exception imbriquée est org.springframework.beans.factory.BeanCreationException: le champ autowire ne peut pas être: privé org.springframework.security.core.userdetails.UserDetailsService com.entirety.app.config.SecurityConfig.userDetailsServiceImplémentation L'exception imbriquée est org.springframework.beans.factory.NoSuchBeanDefinitionException: aucun bean de qualification de type [org.springframework.security.core.userdetails.UserDetailsService] n'a été trouvé pour la dépendance: attendu au moins 1 bean qui se qualifie comme candidat à l'autonomie pour cette dépendance. Annotations de dépendance: {@ org.springframework.beans.factory.annotation.Autowired (required = true)}
J'ai parcouru mon code avec un peigne fin et je ne peux pas identifier le problème.
Version de la structure Spring: 3.2.5.RELEASE Version de la sécurité Spring: 3.2.0.M2
SecurityConfig.Java
package com.entirety.app.config;
import com.entirety.app.service.implement.UserDetailsServiceImplementation;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import javax.sql.DataSource;
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled=true)
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
private DataSource dataSource;
@Autowired
private UserDetailsService userDetailsServiceImplementation;
@Override
protected void registerAuthentication(AuthenticationManagerBuilder auth) throws Exception {
auth.jdbcAuthentication().dataSource(dataSource);
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.userDetailsService(userDetailsServiceImplementation)
.authorizeUrls()
.antMatchers("/admin/**").hasRole("ADMIN")
.antMatchers("/sec/**").hasRole("MODERATOR")
.antMatchers("/*").permitAll()
.anyRequest().anonymous().and().exceptionHandling().accessDeniedPage("/denied").and()
.formLogin()
.loginProcessingUrl("/j_spring_security_check")
.loginPage("/login")
.failureUrl("/error-login")
.and()
.logout()
.logoutUrl("/j_spring_security_logout")
.logoutSuccessUrl("/");
}
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
}
CrmUserService.Java
@Service("userService")
@Transactional
public class CrmUserService implements UserDetailsService {
@Autowired
private UserDAO userDAO;
@Override
public UserDetails loadUserByUsername(String login) throws UsernameNotFoundException {
com.entirety.app.domain.User domainUser = userDAO.getUser(login);
boolean enabled = true;
boolean accountNonExpired = true;
boolean credentialsNonExpired = true;
boolean accountNonLocked = true;
return new User(
domainUser.getLogin(),
domainUser.getPassword(),
enabled,
accountNonExpired,
credentialsNonExpired,
accountNonLocked,
getAuthorities(domainUser.getAuthority().getId())
);
}
public Collection<? extends GrantedAuthority> getAuthorities(Integer role) {
List<GrantedAuthority> authList = getGrantedAuthorities(getRoles(role));
return authList;
}
public List<String> getRoles(Integer role) {
List<String> roles = new ArrayList<String>();
if (role.intValue() == 1) {
roles.add("ROLE_MODERATOR");
roles.add("ROLE_ADMIN");
} else if (role.intValue() == 2) {
roles.add("ROLE_MODERATOR");
}
return roles;
}
public static List<GrantedAuthority> getGrantedAuthorities(List<String> roles) {
List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
for (String role : roles) {
authorities.add(new SimpleGrantedAuthority(role));
}
return authorities;
}
}
Il n’existe aucune raison logique pour laquelle il devrait échouer, mais c’est le cas.
REMARQUE:
Mon IDE peut lier le fil automatique (c'est-à-dire qu'il sait d'où il provient et tout le reste), mais sa compilation échoue.
EDIT 2: J'ai supprimé le code suivant du fichier SecurityConfig.Java
@Autowired
private UserDataService userDataService;
Et l'ajouté à l'un des POJO et des contrôleurs que je connais sont appelés régulièrement et contiennent d'autres services . Dans ce cas-ci, ce code a été collé dans mon fichier baseController.Java qui indique le rendu de la page d'accueil . Le service est compiler correctement et je peux même l'appeler dans le contrôleur.
Le problème n’est donc isolé que dans le fichier de configuration tel que SecurityConfig.Java, c’est la seule fois où il ne fonctionne pas.
EDIT 3: Ajout de fichiers supplémentaires
SecurityInitializer.Java
@Order(2)
public class SecurityInitializer extends AbstractSecurityWebApplicationInitializer {
}
WebInitializer.Java
@Order(1)
public class WebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer {
@Override
protected Class<?>[] getRootConfigClasses() {
return new Class<?>[] { PersistanceConfig.class, SecurityConfig.class }; //To change body of implemented methods use File | Settings | File Templates.
}
@Override
protected Class<?>[] getServletConfigClasses() {
return new Class<?>[] { WebConfig.class };
}
@Override
protected String[] getServletMappings() {
return new String[] {"/"};
}
// @Override
// protected Filter[] getServletFilters() {
// CharacterEncodingFilter characterEncodingFilter = new CharacterEncodingFilter();
// characterEncodingFilter.setEncoding("UTF-8");
// return new Filter[] { characterEncodingFilter};
// }
}
mvc-dispatcher-servlet.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="com.entirety.app"/>
<bean class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/pages/"/>
<property name="suffix" value=".jsp"/>
</bean>
</beans>
web.xml
<web-app version="2.4"
xmlns="http://Java.Sun.com/xml/ns/j2ee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://Java.Sun.com/xml/ns/j2ee
http://Java.Sun.com/xml/ns/j2ee/web-app_2_4.xsd">
<display-name>Spring MVC Application</display-name>
<servlet>
<servlet-name>mvc-dispatcher</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>mvc-dispatcher</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
Il semble que vous ayez de multiples problèmes.
L’application que vous avez créée avait un fichier web.xml qui configurait un DispatcherServlet nommé mvc-dispatcher
. Le mvc-dispatcher
avait une configuration de mvc-dispatcher-servlet.xml
qui chargeait tous les beans du paquetage com.springapp.sectest
. Cela signifie que mvc-dispatcher
peut trouver votre UserDetailsService
.
L'application disposait également d'un AbstractAnnotationConfigDispatcherServletInitializer qui a créé une DispatcherServlet
qui a chargé votre configuration WebConfig
Java. Cette DispatcherServlet
n'a pu voir aucun Bean créé par mvc-dispatcher
.
En bref, vous devez soit configurer une DispatcherServlet
en utilisant web.xml ou AbstractAnnotationConfigDispatcherServletInitializer
et PAS les deux.
Toute configuration dans getRootConfigClasses est généralement appelée configuration racine ou parent et ne peut pas afficher les beans définis dans getServletConfigClasses. Spring Security protège votre application définie dans les getRootConfigClasses avec un filtre nommé springSecurityFilterChain créé par l'annotation @EnableWebSecurity
. Cela signifie qu'il est généralement préférable de placer la configuration de Spring Security dans les getRootConfigClasses. Il existe quelques exceptions à cela, comme si vous souhaitez sécuriser les méthodes sur vos contrôleurs Spring MVC.
Toute configuration dans getServletConfigClasses est généralement appelée configuration enfant et peut afficher les beans définis dans getRootConfigClasses. La méthode getServletConfigClasses configure la DispatcherServlet
et doit contenir des beans pour Spring MVC (c'est-à-dire des contrôleurs, des ViewResovlers, etc.). Tous les beans Spring MVC définis dans getRootConfigClasses sont visibles mais non utilisés.
Cette configuration, même si elle est un peu déroutante, vous permet d’avoir plusieurs instances DispatcherServlet
avec des configurations isolées. En pratique, il est TRÈS rare d'avoir plusieurs instances DispatcherServlet
.
Compte tenu des informations ci-dessus, vous devez déplacer la déclaration UserDetailsService
avec tous ses beans dépendants dans les classes getRootConfig. Cela permettra à SecurityConfig.Java de trouver la UserDetailsService
.
J'ai soumis un PR pour que votre candidature soit enregistrée sans erreur de départ https://github.com/worldcombined/AnnotateFailed/pull/1 . Quelques notes
Basé sur ce commentaire:
@ComponentScan est exécuté dans mon fichier mvc-dispatcher-servlet.xml en tant que <contexte: composant-scan base-package = "com.entirety.app" />
Il semble que vous configuriez les services dans la configuration de Dispatcher et non dans le contexte racine.
La configuration de Spring Security est généralement configurée dans le contexte racine. Par exemple, on pourrait étendre AbstractSecurityWebApplicationInitializer comme indiqué ci-dessous:
import org.springframework.security.web.context.*;
public class SecurityWebApplicationInitializer
extends AbstractSecurityWebApplicationInitializer {
}
Comment importez-vous la configuration de la sécurité? Si la configuration de Spring Security se trouve dans le contexte racine, les beans définis dans le contexte du servlet Dispatcher ne seront pas visibles.
La solution consiste à déplacer la configuration de vos services dans le contexte racine ou à déplacer la configuration de Spring Security vers ApplicationContext du répartiteur. Par exemple, le déplacement de la configuration de Spring Security dans le contexte du distributeur correspond à ce qui suit si votre servlet de distributeur s'appelle mvc.
public class SecurityWebApplicationInitializer
extends AbstractSecurityWebApplicationInitializer {
protected String getDispatcherWebApplicationContextSuffix() {
return "mvc";
}
}
utiliser @ composant pour la classe SecurityConfig
Et si vous essayez d'ajouter cette annotation à la classe SecurityConfig?
@ComponentScan (basePackages = "paquet contenant UserDetailsService")
il devrait être auto-câblé par type mais ...
vous avez nommé votre UserDetailService
@Service("userService")
essayez de nommer votre champ de la même manière
@Autowired
private UserDetailsService userService;