web-dev-qa-db-ja.com

フィールドを自動配線できませんでした:プライベートorg.springframework.security.core.userdetails.UserDetailsS​​ervice

私はSpringを初めて使用するので、セキュリティの面でいじくり回しています。アプリケーションを実行するたびに、次のようになります。

org.springframework.beans.factory.BeanCreationException:「securityConfig」という名前のBeanの作成エラー:自動配線された依存関係の注入に失敗しました。ネストされた例外はorg.springframework.beans.factory.BeanCreationException:フィールドを自動配線できませんでした:private org.springframework.security.core.userdetails.UserDetailsS​​ervice com.entirety.app.config.SecurityConfig.userDetailsS​​erviceImplementation;ネストされた例外はorg.springframework.beans.factory.NoSuchBeanDefinitionExceptionです:タイプ[org.springframework.security.core.userdetails.UserDetailsS​​ervice]の適格Beanが依存関係に見つかりません:この依存関係のautowire候補として適格な少なくとも1つのBeanが必要です。依存関係アノテーション:{@ org.springframework.beans.factory.annotation.Autowired(required = true)}

私は細かい櫛でコードを調べましたが、問題を特定できません。

Spring Frameworkバージョン:3.2.5.RELEASE Spring Securityバージョン: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;
    }
}

それが失敗しなければならない論理的な理由はまだありません。

注意:

私のIDEは、自動配線をリンクできます(つまり、自動配線の開始場所とすべてを認識しています)が、コンパイルに失敗します。

編集2:SecurityConfig.Javaファイルから次のコードを削除しました

@Autowired
private UserDataService userDataService;

そして、それを私が知っているPOJOとコントローラーの1つに追加すると、定期的に呼び出され、他のサービスが含まれます。この場合、ホームページのレンダリングを指示するbaseController.Javaファイルにそのコードを貼り付けました。サービスは適切にコンパイルされており、コントローラー内で呼び出すこともできます。

したがって、問題はSecurityConfig.Javaなどの構成ファイルにのみ分離され、それが機能しないのはこのときだけです。

編集3:追加のファイルを追加

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

更新(完全な例を提供した後)

複数の問題があるようです。

web.xmlとAbstractAnnotationConfigDispatcherServletInitializer

作成したアプリケーションには、mvc-dispatcherという名前のDispatcherServletを構成するweb.xmlがありました。 mvc-dispatcherの構成はmvc-dispatcher-servlet.xmlで、パッケージ内のすべてのBeanをロードしましたcom.springapp.sectest。つまり、mvc-dispatcherはあなたのUserDetailsServiceを見つけることができます。

また、アプリケーションには、DispatcherServlet Java構成をロードするWebConfigを作成したAbstractAnnotationConfigDispatcherServletInitializerがありました。このDispatcherServletは、 mvc-dispatcher

つまり、web.xmlまたはDispatcherServletを使用してAbstractAnnotationConfigDispatcherServletInitializerを構成し、両方を構成する必要はありません。

getRootConfigClassesとgetServletConfigClasses

GetRootConfigClasses内の構成は通常、ルート構成または親構成と呼ばれ、getServletConfigClassesで定義されたBeanを表示できません。 Spring Securityは、getRootConfigClassesで定義されたアプリケーションを、@EnableWebSecurityアノテーションによって作成されたspringSecurityFilterChainという名前のフィルターで保護します。つまり、Spring Securityの構成をgetRootConfigClassesに配置するのが一般的に最善です。 Spring MVCコントローラーでメソッドセキュリティを実行する場合など、これにはいくつかの例外があります。

GetServletConfigClasses内の構成は通常、子構成と呼ばれ、getRootConfigClassesで定義されたBeanを表示できます。 getServletConfigClassesはDispatcherServletを構成し、Spring MVCのBean(つまり、コントローラ、ViewResovlersなど)を含む必要があります。 getRootConfigClassesで定義されたSpring MVC Beanは表示されますが、使用されません。

この設定は少し混乱しますが、分離された構成で複数のDispatcherServletインスタンスを使用できます。しかし実際には、複数のDispatcherServletインスタンスを持つことは非常にまれです。

上記の情報を前提として、UserDetailsService宣言とそれに依存するすべてのBeanをgetRootConfigClassesに移動する必要があります。これにより、SecurityConfig.JavaがUserDetailsServiceを見つけられるようになります。

修正のプルリクエスト

エラーなしで開始するようにアプリケーションを取得するためのPRを提出しました https://github.com/worldcombined/AnnotateFailed/pull/1 。いくつかのメモ

  • テストは親と子のコンテキストを使用しないため、アプリケーションの実行を反映していません
  • 適切にピックアップされるように、resourcesフォルダーを移動する必要がありました。
  • 実際に認証できるように、私はそれをしませんでした。 login.jspはなく、指定したUserDetailsS​​erviceは常にnullを返します。代わりに、ここでエラーが返されたことを実証しようとしました。

元の回答

このコメントに基づいて:

@ComponentScanは、私のmvc-dispatcher-servlet.xmlで<context:component-scan base-package = "com.entirety.app" />として実行されます

ルートコンテキスト内ではなく、Dispatcher構成内でサービスを構成しているようです。

Spring Securityの構成は通常、ルートコンテキストで構成されます。たとえば、次のようにAbstractSecurityWebApplicationInitializerを拡張できます。

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

public class SecurityWebApplicationInitializer
      extends AbstractSecurityWebApplicationInitializer {
}

セキュリティ構成をどのようにインポートしますか? Spring Security構成がルートコンテキストにある場合、Dispatcherサーブレットコンテキストで定義されたBeanは表示されません。

解決策は、サービスの構成をルートコンテキストに移動するか、Spring Security構成をディスパッチャーのApplicationContextに移動することです。たとえば、ディスパッチャサーブレットの名前がmvcの場合、Spring Security構成をディスパッチャコンテキストに移動すると、次のようになります。

public class SecurityWebApplicationInitializer
      extends AbstractSecurityWebApplicationInitializer {
    protected String getDispatcherWebApplicationContextSuffix() {
        return "mvc";
    }
}
15
Rob Winch

securityConfigクラスに@コンポーネントを使用する

0
Abhinav Jayaram

このアノテーションをSecurityConfigクラスに追加してみますか?

@ComponentScan(basePackages = "UserDetailsS​​erviceを含むパッケージ")

0
indybee

タイプによって自動配線されますが...

あなたはあなたのUserDetailServiceに名前を付けました

@Service("userService")

フィールドに同じ名前を付けてみてください

@Autowired
private UserDetailsService userService;
0
freakman