如何使用SpringSecurity3和hibernate 4将springsecurityxml配置hibernate



我刚刚学习了spring安全性,并希望使用java hibernate配置连接到数据库,但我发现很少有示例或教程。通过使用xml配置,我发现了更多。我在这里使用的是Spring 4.0.2、Spring Security 3.2.0和Hibernate 4.3.2

我的问题是:以下xml是如何转换为java配置的

<authentication-manager>
<authentication-provider user-service-ref="customUserDetailsService">
<password-encoder hash="plaintext">
</password-encoder></authentication-provider>
</authentication-manager>

其中CustomUserDetailsService.java

package com.whatever.svtest.service.impl;
import java.util.ArrayList;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import com.whatever.svtest.dao.UserDao;
@Service
@Transactional(readOnly = true)
public class CustomUserDetailsService implements UserDetailsService {
@Autowired
private UserDao userDao;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
com.whatever.svtest.model.User domainUser = userDao.getByUsername(username);
if (domainUser == null) {
throw new UsernameNotFoundException("user not found");
}
List<SimpleGrantedAuthority> authorities = new ArrayList<SimpleGrantedAuthority>();
authorities.add(new SimpleGrantedAuthority("USER"));        
return new User(username, domainUser.getPassword(), true, true, true, true, authorities);
}
}

在SecurityConfig.java上,我使用spring创建的默认登录表单。我正试图自己弄清楚如何将xml配置转换为java配置。

package com.whatever.svtest.init;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
import com.whatever.svtest.service.impl.UserServiceImpl;
@Configuration
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(new UserServiceImpl()).passwordEncoder(NoOpPasswordEncoder.getInstance());
}
}

我把SecurityConfiguration.java放在Initializer.java上,就像这个一样

package com.whatever.svtest.init;
import javax.servlet.Filter;
import org.springframework.web.filter.DelegatingFilterProxy;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
public class Initializer extends AbstractAnnotationConfigDispatcherServletInitializer {
@Override
protected Class<?>[] getRootConfigClasses() {
// return null;
return new Class[] { SecurityConfiguration.class };
}
@Override
protected Class<?>[] getServletConfigClasses() {
return new Class<?>[] { WebAppConfig.class };
}
@Override
protected String[] getServletMappings() {
return new String[] { "/" };
}
@Override
protected Filter[] getServletFilters() {
return new Filter[] { new DelegatingFilterProxy("springSecurityFilterChain") };
}
}

WebAppConfig.java

package com.whatever.svtest.init;
import javax.annotation.Resource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.context.annotation.PropertySource;
import org.springframework.context.support.ResourceBundleMessageSource;
import org.springframework.core.env.Environment;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
@Configuration
@EnableWebMvc
@Import({ DatabaseConfig.class })
@ComponentScan(basePackages = { "com.whatever.svtest.controller" })
@PropertySource({ "classpath:persistence-mysql.properties" })
public class WebAppConfig extends WebMvcConfigurerAdapter {
@Resource   
private Environment env;
@Override   
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/assets/**").addResourceLocations("/assets/");
}
@Bean
public ResourceBundleMessageSource messageSource() {
ResourceBundleMessageSource source = new ResourceBundleMessageSource();
source.setBasename("messages");
source.setUseCodeAsDefaultMessage(true);
return source;
}
@Bean
public ViewResolver setupViewResolver() {
InternalResourceViewResolver resolver = new InternalResourceViewResolver();
resolver.setPrefix("/WEB-INF/view/");
resolver.setSuffix(".jsp");
return resolver;
}
}

当我运行我的网络应用程序时,我得到了这个。(我把图片放在这里https://i.stack.imgur.com/Mssrc.jpg)

我也读过(某个地方)关于创建AuthenticationProvider.java的自定义实现的文章,但我不知道该把这些代码放在哪里。。

package com.whatever.svtest.init;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import com.whatever.svtest.dao.UserDao;
import com.whatever.svtest.model.User;
public class MyAuthProvider implements AuthenticationProvider {
@Autowired
private UserDao userDao;
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
String name = authentication.getName();
String password = authentication.getCredentials().toString();
User user = userDao.getByUsername(name);
authentication.setAuthenticated(user != null && password.equals(user.getPassword()));
return authentication;
}
@Override
public boolean supports(Class<?> authentication) {
return (MyAuthProvider.class.isAssignableFrom(authentication));
}
}

配置不一致

你发布的配置对我来说不太有意义。具体如下:

protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(new UserServiceImpl()).passwordEncoder(NoOpPasswordEncoder.getInstance());
}

解决方案

你似乎还没有定义UserServiceImpl,但你已经定义了CustomUserDetailsService(这可能是应该传入的参数。然而,为了使bean自动连接,你需要将其创建为bean。因此,你应该这样更改配置:

protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(uds());
}
@Bean
public CustomUserDetailsService uds() {
return new CustomUserDetailsService();
}

通过以@Bean的形式返回CustomUserDetailsService,可以确保Spring正确地自动连接它。

一些附加说明:

  • 您不需要自定义AuthenticationProvider。这是因为您使用用户名/密码进行身份验证,所以UserDetailsService可以。如果您想使用用户名/密码以外的其他东西进行身份验证,您可以创建一个自定义AuthenticationProvider
  • 无需指定无操作密码编码器,因为这是默认设置

改进CustomUserDetailsService

对于当前的实现,需要指出的一点是,虽然您可以直接@Autowire字段,但这会使出错变得更容易,因此您可能应该更改CustomUserDetailsService,使其具有允许注入UserDao的构造函数。这也使单元测试变得更容易(因此您不需要使用反射来设置UserDao)。因此,您将更新CustomUserDetailsService为:

@Service
@Transactional(readOnly = true)
public class CustomUserDetailsService implements UserDetailsService {
private UserDao userDao;
@Autowired
public CustomUserDetailsService(UserDao userDao) {
this.userDao = userDao;
}

然后您的配置可以如下:

protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(uds());
}
@Autowired
private UserDao userDao;
@Bean
public CustomUserDetailsService uds() {
return new CustomUserDetailsService(userDao);
}

根据新错误进行更新

您还需要确保您的UserDao被选为Bean。例如:

@Bean
public UserDao userDao() {
return new UserDao(...);
}

注意:请确保正确初始化UserDao(即确保其所有依赖项都已初始化。如果在UserDao上使用Autowired,请确保这些依赖项也是@Bean

[已解决]

在与自己的代码finnaly斗争了两天后,我找到了解决方案。。!

@Configuration
@EnableWebSecurity
@ComponentScan(basePackageClasses = SecurityConfiguration.class)
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
@Autowired
private UserService userService;
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userService);
}
}

我不必创建新的bean。我只需要将UserService对象传递到userDetailsService方法中,将自动连接,当然使用@ComponentScan到当前类UserService类已经有一个UserDao,并且我在其中实现了UserDetailsService

@Service("userService")
@Transactional(readOnly = true)
public class UserServiceImpl implements UserService, UserDetailsService {
@Autowired
private UserDao userDao;
// other method
@Override
public User getByUsername(String username) {
return userDao.getByUsername(username);
}
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
User user = getByUsername(username);
if (user == null) {
throw new UsernameNotFoundException("user not found");
} else {
List<GrantedAuthority> listAuthorities = new ArrayList<GrantedAuthority>();
listAuthorities.add(new SimpleGrantedAuthority("ROLE_USER"));
return new org.springframework.security.core.userdetails.User(username, user.getPassword(), true, true, true, true, listAuthorities);
}
}
}

感谢Rob Winch提供的线索。

最新更新