it-swarm.com.de

Feld konnte nicht automatisch aktiviert werden: privates org.springframework.security.core.userdetails.UserDetailsService

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>
9
Aeseir

Update (nach vollständigem Beispiel)

Es scheint, Sie haben mehrere Probleme.

web.xml vs AbstractAnnotationConfigDispatcherServletInitializer

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.

getRootConfigClasses vs getServletConfigClasses

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.

Pull Request für Fixes

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

  • der Test verwendet keinen übergeordneten und untergeordneten Kontext, sodass die Ausführung der Anwendung nicht angezeigt wird
  • Ich musste den Ressourcenordner verschieben, damit er richtig aufgenommen wurde
  • Ich habe es nicht gemacht, damit Sie sich tatsächlich authentifizieren können. Es gab kein login.jsp und der von Ihnen angegebene UserDetailsService gibt immer null zurück. Stattdessen habe ich versucht zu zeigen, dass der Fehler hier beantwortet wurde.

Ursprüngliche Antwort

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";
    }
}
15
Rob Winch

verwenden Sie die @ -Komponente für die SecurityConfig-Klasse

0
Abhinav Jayaram

Was ist, wenn Sie diese Anmerkung zur SecurityConfig-Klasse hinzufügen möchten?

@ComponentScan (basePackages = "Paket mit UserDetailsService")

0
indybee

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;
0
freakman