如何使用 Spring-Security 3 和 Hibernate 4 将 spring security xml 配置 hibernate 转换为 java config
Posted
技术标签:
【中文标题】如何使用 Spring-Security 3 和 Hibernate 4 将 spring security xml 配置 hibernate 转换为 java config【英文标题】:How to convert the spring security xml configuration hibernate into java config using Spring-Security 3 and Hibernate 4 【发布时间】:2014-04-06 06:25:42 【问题描述】:我刚刚了解了 Spring Security,并想使用 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;
当我运行我的网络应用程序时,我得到了这个。 (我把图片放在这里http://i.stack.imgur.com/Ms-s-rc.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));
【问题讨论】:
我能知道您为什么特别寻找注解来配置 Spring Security 吗?至少对于 Spring Security 而言,将其作为 xml 配置具有更大的优势,这使得在不触及现有代码的情况下可以灵活地更改它。您可以在此链接中获得一些编程配置***.com/questions/19353578/… 嗨,杰伊,我没有理由“为什么”。我是spring框架的新人。我刚从 3 周前开始学习 Spring Framework。最近我看到了很多变化。一切都从 xml 转换为 java 配置。所以,我为什么不学习最新的.. :) 【参考方案1】:[已解决]
在为自己的代码苦苦挣扎两天后,我终于找到了解决方案..!
@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 方法,放入 autowired,当然使用 @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 提供线索。
【讨论】:
【参考方案2】:配置不一致?
您发布的配置对我来说不太有意义。具体如下:
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();
通过将 CustomUserDetailsService 作为 @Bean 返回,您可以确保 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
。
【讨论】:
感谢您的回答。我听从你的指示。但它仍然无法正常工作。我收到错误 pastebin.com/htHBH5RN 我发现这个链接 (***.com/questions/8162698/…) 虽然它不使用休眠,但它解决了我的问题,但正如你所说的“我不需要自定义”AuthenticationProvider,它让我更加困惑。跨度> 您的 UserDao 也需要定义为 Bean。查看我的更新以上是关于如何使用 Spring-Security 3 和 Hibernate 4 将 spring security xml 配置 hibernate 转换为 java config的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 spring-security 和 jQuery 处理过期会话?
spring-security 收到空凭据(用户名和密码)时如何创建自定义响应?
如何使用 Spring-Boot 播种 Spring-Security
如何使用我自己的机制自定义 spring-security 身份验证过程