Ich bin neu bei Spring, also habe ich mich mit Sicherheitskopien herumgespielt ... Jedes Mal, wenn ich meine Anwendung starte, bekomme ich:
org.springframework.beans.factory.BeanCreationException: Fehler beim Erstellen der Bean mit dem Namen 'securityConfig': Die Injektion von autowired Abhängigkeiten ist fehlgeschlagen. geschachtelte Ausnahme ist org.springframework.beans.factory.BeanCreationException: Feld konnte nicht automatisch aktiviert werden: privates org.springframework.security.core.userdetails.UserDetailsService com.entirety.app.config.SecurityConfig.userDetailsServiceImplementation; Die verschachtelte Ausnahme ist org.springframework.beans.factory.NoSuchBeanDefinitionException: Keine qualifizierende Bean vom Typ [org.springframework.security.core.userdetails.UserDetailsService] für Abhängigkeit gefunden: Es wird mindestens eine Bean erwartet, die als autowire-Kandidat für diese Abhängigkeit qualifiziert ist. Abhängigkeitsanmerkungen: {@ org.springframework.beans.factory.annotation.Autowired (required = true)}
Ich habe meinen Code mit einem feinen Kamm durchgesehen und kann das Problem nicht genau bestimmen.
Spring Framework-Version: 3.2.5.RELEASE Spring-Sicherheitsversion: 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;
}
}
Es gibt keinen logischen Grund, warum es versagen sollte, aber es tut es.
HINWEIS:
Meine IDE kann die Autowire verbinden (dh sie weiß, wo sie automatisch abgehängt wird und alles), aber das Kompilieren schlägt fehl.
BEARBEITEN 2: Ich habe den folgenden Code aus der Datei SecurityConfig.Java entfernt
@Autowired
private UserDataService userDataService;
Und fügte es zu einem der POJOs und Controller hinzu, von denen ich weiß, dass sie regelmäßig aufgerufen werden und andere Services enthalten. In diesem Fall fügte ich diesen Code in meine baseController.Java-Datei ein, die zum Rendern der Startseite führt. Der Service ist richtig kompilieren und ich kann es sogar innerhalb des Controllers aufrufen.
Das Problem wird also nur von der Konfigurationsdatei wie SecurityConfig.Java isoliert, das ist das einzige Mal, dass es nicht funktioniert.
EDIT 3: Zusätzliche Dateien hinzugefügt
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>
Es scheint, Sie haben mehrere Probleme.
Die von Ihnen erstellte Anwendung hatte eine web.xml, die ein DispatcherServlet mit dem Namen mvc-dispatcher
konfiguriert. mvc-dispatcher
hatte eine Konfiguration von mvc-dispatcher-servlet.xml
, mit der alle Beans im Paket com.springapp.sectest
geladen wurden. Dies bedeutet, dass mvc-dispatcher
Ihre UserDetailsService
finden kann.
Die Anwendung hatte auch einen AbstractAnnotationConfigDispatcherServletInitializer, der eine DispatcherServlet
erstellt hat, mit der Ihre WebConfig
Java-Konfiguration geladen wurde. Diese DispatcherServlet
konnte keine Beans sehen, die von mvc-dispatcher
erstellt wurden.
Kurz gesagt, Sie sollten entweder eine DispatcherServlet
mit web.xml oder AbstractAnnotationConfigDispatcherServletInitializer
und NICHT beide konfigurieren.
Jede Konfiguration in getRootConfigClasses wird normalerweise als Root- oder Parent-Konfiguration bezeichnet und kann keine in getServletConfigClasses definierten Beans anzeigen. Spring Security schützt Ihre in getRootConfigClasses definierte Anwendung mit einem Filter mit dem Namen springSecurityFilterChain, der von der @EnableWebSecurity
-Annotation erstellt wird. Daher ist es im Allgemeinen am besten, die Konfiguration von Spring Security in den getRootConfigClasses zu platzieren. Es gibt einige Ausnahmen, zum Beispiel, wenn Sie die Methodensicherheit für Ihre Spring MVC-Controller ausführen möchten.
Jede Konfiguration in getServletConfigClasses wird normalerweise als untergeordnete Konfiguration bezeichnet und kann Beans anzeigen, die in getRootConfigClasses definiert sind. Die getServletConfigClasses konfiguriert die DispatcherServlet
und muss Beans für Spring MVC (d. H. Controller, ViewResovlers usw.) enthalten. Alle in getRootConfigClasses definierten Spring-MVC-Beans sind sichtbar, werden jedoch nicht verwendet.
Während dieses Setups ein wenig verwirrend ist, können Sie mehrere DispatcherServlet
-Instanzen mit isolierten Konfigurationen verwenden. In der Praxis ist es jedoch sehr selten, mehrere DispatcherServlet
-Instanzen zu haben.
In Anbetracht der obigen Informationen sollten Sie die Deklaration UserDetailsService
zusammen mit allen abhängigen Beans in die getRootConfigClasses verschieben. Dadurch wird sichergestellt, dass die SecurityConfig.Java die UserDetailsService
findet.
Ich habe eine PR eingereicht, um Ihre Bewerbung so zu erhalten, dass sie ohne Fehler beginnt https://github.com/worldcombined/AnnotateFailed/pull/1 . Ein paar Notizen
Basierend auf diesem Kommentar:
@ComponentScan wird in meiner mvc-dispatcher-servlet.xml als .__ übernommen. <context: component-scan base-package = "com.entirety.app" />
Es scheint, dass Sie die Dienste in der Dispatcher-Konfiguration und nicht im Stammkontext konfigurieren.
Die Konfiguration von Spring Security wird normalerweise im Root-Kontext konfiguriert. Beispielsweise könnte man den AbstractSecurityWebApplicationInitializer wie folgt erweitern:
import org.springframework.security.web.context.*;
public class SecurityWebApplicationInitializer
extends AbstractSecurityWebApplicationInitializer {
}
Wie importieren Sie die Sicherheitskonfiguration? Wenn sich die Spring Security-Konfiguration im Stammkontext befindet, werden keine im Dispatcher Servlet-Kontext definierten Beans angezeigt.
Die Lösung besteht darin, die Konfiguration Ihrer Services in den Stammkontext zu verschieben oder die Spring Security-Konfiguration in den ApplicationContext des Dispatchers zu verschieben. Wenn Sie beispielsweise die Konfiguration von Spring Security in den Dispatcher-Kontext verschieben, würde das folgende aussehen, wenn Ihr Dispatcher-Servlet den Namen mvc hatte.
public class SecurityWebApplicationInitializer
extends AbstractSecurityWebApplicationInitializer {
protected String getDispatcherWebApplicationContextSuffix() {
return "mvc";
}
}
verwenden Sie die @ -Komponente für die SecurityConfig-Klasse
Was ist, wenn Sie diese Anmerkung zur SecurityConfig-Klasse hinzufügen möchten?
@ComponentScan (basePackages = "Paket mit UserDetailsService")
es sollte automatisch nach Typ sein, aber ...
sie haben Ihren UserDetailService benannt
@Service("userService")
versuchen Sie, Ihr Feld gleich zu benennen
@Autowired
private UserDetailsService userService;