Я озадачен SpringSecurity. Есть много способов реализовать простую вещь, и я их все перепутал.
Мой код выглядит следующим образом, но он вызывает исключение. Если я удалю UserDetailsService
связанные коды, приложение запустится, и я смогу войти в систему in-memory
пользователей. Как было предложено ниже, я преобразовал конфигурацию в формат XML, но пользователи не могут выполнить вход.
org.springframework.beans.factory.BeanCreationException: Error creating bean
with name 'securityConfig': Injection of autowired dependencies failed; nested
exception is org.springframework.beans.factory.BeanCreationException: Could
not autowire field:
org.springframework.security.core.userdetails.UserDetailsService
com.myproj.config.SecurityConfig.userDetailsService; nested exception is
org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying
bean of type
[org.springframework.security.core.userdetails.UserDetailsService] found for
dependency: expected at least 1 bean which qualifies as autowire candidate for
this dependency. Dependency annotations:
{@org.springframework.beans.factory.annotation.Autowired(required=true),
@org.springframework.beans.factory.annotation.Qualifier(value=userDetailsService)}
Caused by: org.springframework.beans.factory.BeanCreationException: Could not
autowire field
org.springframework.security.core.userdetails.UserDetailsService
com.myproj.config.SecurityConfig.userDetailsService; nested exception is
org.springframework.beans.factory.NoSuchBeanDefinitionException:
No qualifying bean of type
[org.springframework.security.core.userdetails.UserDetailsService]
found for dependency: expected at least 1 bean which qualifies as autowire
candidate for this dependency. Dependency annotations:
{@org.springframework.beans.factory.annotation.Autowired(required=true),
@org.springframework.beans.factory.annotation.Qualifier(value=userDetailsService)}
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException:
No qualifying bean of type
[org.springframework.security.core.userdetails.UserDetailsService] found for
dependency: expected at least 1 bean which qualifies as autowire candidate for
this dependency. Dependency annotations:
{@org.springframework.beans.factory.annotation.Autowired(required=true),
@org.springframework.beans.factory.annotation.Qualifier(value=userDetailsService)}
web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee
http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"
version="3.0">
<listener>
<listener-class>org.apache.tiles.extras.complete.CompleteAutoloadTilesListener</listener-class>
</listener>
<servlet>
<servlet-name>proj</servlet-name>
<servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>
<load-on-startup>1</load-on-startup>
</servlet>
<servlet-mapping>
<servlet-name>proj</servlet-name>
<url-pattern>/</url-pattern>
</servlet-mapping>
</web-app>
MvcWebApplicationInitializer
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
public class MvcWebApplicationInitializer
extends AbstractAnnotationConfigDispatcherServletInitializer {
@Override
protected Class<?>[] getRootConfigClasses() {
return new Class[] { SecurityConfig.class };
}
@Override
protected Class<?>[] getServletConfigClasses() {
return null;
}
@Override
protected String[] getServletMappings() {
return new String[] { "/" };
}
}
SecurityWebApplicationInitializer
import org.springframework.security.web.context.AbstractSecurityWebApplicationInitializer;
public class SecurityWebApplicationInitializer
extends AbstractSecurityWebApplicationInitializer {
}
SecurityConfig
@Configuration
@EnableWebMvcSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
@Qualifier("userDetailsService")
UserDetailsService userDetailsService;
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth)
throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(
passwordEncoder());
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/resources/**", "/", "/index", "/aboutus")
.permitAll()
.antMatchers("/profile/**")
.hasRole("USER")
.and()
.formLogin().loginPage("/signin").failureUrl("/signin?error")
.permitAll().and().logout().logoutUrl("/signout").permitAll();
}
@Bean
public PasswordEncoder passwordEncoder() {
PasswordEncoder encoder = new BCryptPasswordEncoder();
return encoder;
}
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception
{
return super.authenticationManagerBean();
}
}
MemberServiceImpl
@Service("userDetailsService")
public class MemberServiceImpl implements UserDetailsService {
@Autowired
MemberRepository memberRepository;
private List<GrantedAuthority> buildUserAuthority(String role) {
Set<GrantedAuthority> setAuths = new HashSet<GrantedAuthority>();
setAuths.add(new SimpleGrantedAuthority(role));
List<GrantedAuthority> result = new ArrayList<GrantedAuthority>(
setAuths);
return result;
}
private User buildUserForAuthentication(Member member,
List<GrantedAuthority> authorities) {
return new User(member.getEmail(), member.getPassword(),
member.isEnabled(), true, true, true, authorities);
}
@Override
@Transactional(readOnly = true)
public UserDetails loadUserByUsername(String username)
throws UsernameNotFoundException {
Member member = memberRepository.findByUserName(username);
List<GrantedAuthority> authorities = buildUserAuthority("Role");
return buildUserForAuthentication(member, authorities);
}
}
Обновление 1
Даже после добавления следующей аннотации и метода authenticationManagerBean
из SecurityConfig создается одно и то же исключение.
@EnableGlobalMethodSecurity(prePostEnabled = true)
Обновление 2
Как было предложено в одном из ответов, я преобразовал его в конфигурацию на основе XML, текущий код выглядит следующим образом, однако при отправке формы входа ничего не делает.
Spring -Security.xml
<beans:beans xmlns="http://www.springframework.org/schema/security"
xmlns:beans="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/security
http://www.springframework.org/schema/security/spring-security-3.0.xsd">
<beans:import resource='login-service.xml' />
<http auto-config="true" access-denied-page="/notFound.jsp"
use-expressions="true">
<intercept-url pattern="/" access="permitAll" />
<form-login login-page="/signin" authentication-failure-url="/signin?error=1"
default-target-url="/index" />
<remember-me />
<logout logout-success-url="/index.jsp" />
</http>
<authentication-manager>
<authentication-provider>
<!-- <user-service> <user name="admin" password="secret" authorities="ROLE_ADMIN"/>
<user name="user" password="secret" authorities="ROLE_USER"/> </user-service> -->
<jdbc-user-service data-source-ref="dataSource"
users-by-username-query="
select username,password,enabled
from Member where username=?"
authorities-by-username-query="
select username
from Member where username = ?" />
</authentication-provider>
</authentication-manager>
</beans:beans>
Логин-service.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost/testProject" />
<property name="username" value="root" />
<property name="password" value="" />
</bean>
</beans>