UserDetailsService介绍:
UserDetailsService接口如下:
Spring Security 提供了以下实现:(基于内存、缓存和JDBC)
上面接口返回一个UserDetails,这也是一个接口
public interface UserDetails extends Serializable {
/**
* Returns the authorities granted to the user. Cannot return <code>null</code>.
* @return the authorities, sorted by natural key (never <code>null</code>)
*/
Collection<? extends GrantedAuthority> getAuthorities();
/**
* Returns the password used to authenticate the user.
* @return the password
*/
String getPassword();
/**
* Returns the username used to authenticate the user. Cannot return
* <code>null</code>.
* @return the username (never <code>null</code>)
*/
String getUsername();
/**
* Indicates whether the user's account has expired. An expired account cannot be
* authenticated.
* @return <code>true</code> if the user's account is valid (ie non-expired),
* <code>false</code> if no longer valid (ie expired)
*/
boolean isAccountNonExpired();
/**
* Indicates whether the user is locked or unlocked. A locked user cannot be
* authenticated.
* @return <code>true</code> if the user is not locked, <code>false</code> otherwise
*/
boolean isAccountNonLocked();
/**
* Indicates whether the user's credentials (password) has expired. Expired
* credentials prevent authentication.
* @return <code>true</code> if the user's credentials are valid (ie non-expired),
* <code>false</code> if no longer valid (ie expired)
*/
boolean isCredentialsNonExpired();
/**
* Indicates whether the user is enabled or disabled. A disabled user cannot be
* authenticated.
* @return <code>true</code> if the user is enabled, <code>false</code> otherwise
*/
boolean isEnabled();
}
Spring Security 提供了UserDetails 的实现类 User。
UserDetailService的作用
那么这个UserDetailService作用究竟是什么?通过debug分析:
1、写一个UserDetails的实现类,并注入到spring容器中:
package com.xxx.springsecuritydemo.service;
import org.springframework.security.core.authority.AuthorityUtils;
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;
/**
* @Author zongzhibin
* @Date 2021/9/15 14:13
*/
@Service
public class UserService implements UserDetailsService {
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
System.out.println("");
return new User("admin","123", AuthorityUtils.commaSeparatedStringToAuthorityList("admin"));
}
}
2、启动项目,发现这个类调用的地方为
注意这里只是返回一个User类,真正密码比对的地方在
additionalAuthenticationChecks(user, (UsernamePasswordAuthenticationToken) authentication);
方法中:
结论:Spring Security 会将前端填写的username 传给 UserDetailService.loadByUserName 方法。我们只需要从数据库中根据用户名查找到用户信息然后封装为UserDetails的实现类返回给SpringSecurity 即可,咱们自己不需要进行密码的比对工作,密码比对交由SpringSecurity 处理。
关于PasswordEncoder:
当然咱们数据库中的用户的密码必须是通过SpringSecurity 指定的
PasswordEncoder 进行加密后保存,因为SpringSecurity 进行密码比对的时候会用相同的PasswordEncoder。
SpringSecurity没有默认的PasswordEncoder,需要用户指定:
那生成用户的时候,密码进行加密: