使用 Hibernate 的 Spring Security 3 数据库身份验证
Posted
技术标签:
【中文标题】使用 Hibernate 的 Spring Security 3 数据库身份验证【英文标题】:Spring Security 3 database authentication with Hibernate 【发布时间】:2011-02-10 14:47:59 【问题描述】:我需要对数据库中的用户进行身份验证,Spring Security 文档没有说明如何使用 hibernate 进行身份验证。这可能吗?我该怎么做?
【问题讨论】:
见***.com/questions/2318467/… 【参考方案1】:您必须创建自己的自定义身份验证提供程序。
示例代码:
从 Hibernate 加载用户的服务:
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
@Service("userDetailsService")
public class UserDetailsServiceImpl implements UserDetailsService
@Autowired private UserDao dao;
@Autowired private Assembler assembler;
@Transactional(readOnly = true)
public UserDetails loadUserByUsername(String username)
throws UsernameNotFoundException, DataAccessException
UserDetails userDetails = null;
UserEntity userEntity = dao.findByName(username);
if (userEntity == null)
throw new UsernameNotFoundException("user not found");
return assembler.buildUserFromUserEntity(userEntity);
将您的实体转换为弹簧用户对象的服务:
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.GrantedAuthorityImpl;
import org.springframework.security.core.userdetails.User;
@Service("assembler")
public class Assembler
@Transactional(readOnly = true)
User buildUserFromUserEntity(UserEntity userEntity)
String username = userEntity.getName();
String password = userEntity.getPassword();
boolean enabled = userEntity.isActive();
boolean accountNonExpired = userEntity.isActive();
boolean credentialsNonExpired = userEntity.isActive();
boolean accountNonLocked = userEntity.isActive();
Collection<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
for (SecurityRoleEntity role : userEntity.getRoles())
authorities.add(new GrantedAuthorityImpl(role.getRoleName()));
User user = new User(username, password, enabled,
accountNonExpired, credentialsNonExpired, accountNonLocked, authorities, id);
return user;
基于命名空间的 application-context-security.xml 看起来像:
<http>
<intercept-url pattern="/login.do*" filters="none"/>
<intercept-url pattern="/**" access="IS_AUTHENTICATED_ANONYMOUSLY" />
<form-login login-page="/login.do"
authentication-failure-url="/login.do?error=failed"
login-processing-url="/login-please.do" />
<logout logout-url="/logoff-please.do"
logout-success-url="/logoff.html" />
</http>
<beans:bean id="daoAuthenticationProvider"
class="org.springframework.security.authentication.dao.DaoAuthenticationProvider">
<beans:property name="userDetailsService" ref="userDetailsService"/>
</beans:bean>
<beans:bean id="authenticationManager"
class="org.springframework.security.authentication.ProviderManager">
<beans:property name="providers">
<beans:list>
<beans:ref local="daoAuthenticationProvider" />
</beans:list>
</beans:property>
</beans:bean>
<authentication-manager>
<authentication-provider user-service-ref="userDetailsService">
<password-encoder hash="md5"/>
</authentication-provider>
</authentication-manager>
【讨论】:
感谢您提供完整代码的详细解答。你能告诉我为什么需要 Assembler 类,为什么不能把代码放在 loadUserByUsername 方法中?? 你说得对,实际上并不需要汇编程序。只是认为保持 userDetailsService 简单并通过汇编服务使转换可重用是个好主意。 自动装配如何为 userDetailsService 工作,我的自动装配不起作用。我必须在安全 xml 中定义 userDetailsService bean。任何想法。自动装配工作的其他地方 @Nikola 如果密码(哈希)匹配,您不会检查自己,Spring Security 会自动为您执行此操作。如果密码错误,则 Spring Security 重定向到 Spring Security XML 配置中定义的错误密码 URL。您只需要提供 User 对象,其中密码通过正确的散列算法进行散列。如果需要,您也可以使用密码盐,但这需要更多配置。GrantedAuthorityImpl
已弃用,请改用SimpleGrantedAuthority
【参考方案2】:
Java 配置可能看起来像这样
@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter
@Autowired
private UserDetailsServiceImpl userDetailsService;
@Autowired
public void configureGlobal(AuthenticationManagerBuilder auth)
throws Exception
DaoAuthenticationProvider daoAuthenticationProvider =
new DaoAuthenticationProvider();
daoAuthenticationProvider
.setUserDetailsService(userDetailsService);
auth.authenticationProvider(daoAuthenticationProvider);
【讨论】:
【参考方案3】:如果您使用的是 JDBC 可访问数据库,那么您可以使用以下身份验证提供程序并避免创建自定义提供程序。它将所需的代码减少到 9 行 XML:
<authentication-provider>
<jdbc-user-service data-source-ref="dataSource" users-by-username-query="select username,password from users where username=?" authorities-by-username-query="select u.username, r.authority from users u, roles r where u.userid = r.userid and u.username =?" />
</authentication-provider>
然后您可以按如下方式设置数据源
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3306/DB_NAME" />
<property name="username" value="root" />
<property name="password" value="password" />
</bean>
看看这个帖子:http://codehustler.org/blog/spring-security-tutorial-form-login/ 它涵盖了您需要了解的有关自定义 Spring Security 表单登录的所有信息。
【讨论】:
我们可以将它与散列密码一起使用吗? 您应该能够使用 标签中的以上是关于使用 Hibernate 的 Spring Security 3 数据库身份验证的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 Thymeleaf 配置 Spring Boot 并使用 sec:authentication 标签
如何在 Spring sec 中为组使用属性:hasAnyRole 的授权标签