私はSpringを初めて使用するので、セキュリティの面でいじくり回しています。アプリケーションを実行するたびに、次のようになります。
org.springframework.beans.factory.BeanCreationException:「securityConfig」という名前のBeanの作成エラー:自動配線された依存関係の注入に失敗しました。ネストされた例外はorg.springframework.beans.factory.BeanCreationException:フィールドを自動配線できませんでした:private org.springframework.security.core.userdetails.UserDetailsService com.entirety.app.config.SecurityConfig.userDetailsServiceImplementation;ネストされた例外はorg.springframework.beans.factory.NoSuchBeanDefinitionExceptionです:タイプ[org.springframework.security.core.userdetails.UserDetailsService]の適格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>
複数の問題があるようです。
作成したアプリケーションには、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で定義された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 。いくつかのメモ
このコメントに基づいて:
@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";
}
}
securityConfigクラスに@コンポーネントを使用する
このアノテーションをSecurityConfigクラスに追加してみますか?
@ComponentScan(basePackages = "UserDetailsServiceを含むパッケージ")
タイプによって自動配線されますが...
あなたはあなたのUserDetailServiceに名前を付けました
@Service("userService")
フィールドに同じ名前を付けてみてください
@Autowired
private UserDetailsService userService;