上章硬编码了一个user用户。记录一点基础的配置,这次结合高级认证灵活使用Spring Security的用户认证。
-
AuthenticationManager
: 身份验证的主要策略设置接口 -
ProviderManager
:AuthenticationManager
最常用的接口实现 -
AuthenticationProvider
:ProviderManager
的工作被委托者 -
Authentication
: 认证用户信息主体 -
GrantedAuthority
: 用户主体的权限 -
UserDetails
: 用户的基本必要信息 -
UserDetailsService
: 通过String username
返回一个UserDetails
-
SecurityContextHolder
: 提供访问SecurityContext
。 -
SecurityContext
: 保存Authentication
,和一些其它的信息
1. AuthenticationProvider
ProviderManager
把工作委托给AuthenticationProvider
集合。ProviderManager
将所有AuthenticationProvider
进行循环,直到运行返回一个完整的Authentication
,不符合条件或者不能认证当前Authentication
,返回AuthenticationException
异常或者null
。
@Component
public class SpringAuthenticationProvider implements AuthenticationProvider {
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
Assert.isInstanceOf(UsernamePasswordAuthenticationToken.class, authentication, "非验证类型");
//账号
String username = authentication.getName();
//密码
String password = authentication.getCredentials().toString();
List<SimpleGrantedAuthority> roles = new ArrayList<>();
if("testuser1".equalsIgnoreCase(username)){
roles.add(new SimpleGrantedAuthority("ROLE_ADMIN"));
}else if("testuser2".equalsIgnoreCase(username)){
roles.add(new SimpleGrantedAuthority("ROLE_ADMIN"));
roles.add(new SimpleGrantedAuthority("ROLE_DBA"));
}else{
throw new UsernameNotFoundException("用户名/密码无效");
}
return new UsernamePasswordAuthenticationToken(username, password, roles);
}
@Override
public boolean supports(Class<?> authentication) {
return (UsernamePasswordAuthenticationToken.class
.isAssignableFrom(authentication));
}
}
2. UserDetailsService
实现UserDetailsService
方法,提供UserDetails
。
我们把上面的用户登录的查询功能挪动到UserDetailsSerivce
接口实现中。
@Service
public class SpringUserDetailsService implements UserDetailsService {
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
UserDetails userDetails = null;
List<GrantedAuthority> roles = new ArrayList<>();
if ("testuser1".equalsIgnoreCase(username)) {
roles.add(new SimpleGrantedAuthority("ROLE_ADMIN"));
} else if ("testuser2".equalsIgnoreCase(username)) {
roles.add(new SimpleGrantedAuthority("ROLE_ADMIN"));
roles.add(new SimpleGrantedAuthority("ROLE_DBA"));
} else {
return null;
}
userDetails = new User(username, "password", roles);
return userDetails;
}
}
之后再对认证代码进行改动。
@Component
public class SpringAuthenticationProvider implements AuthenticationProvider {
@Autowired
private UserDetailsService userDetailsService;
@Override
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
Assert.isInstanceOf(UsernamePasswordAuthenticationToken.class, authentication, "非验证类型");
//账号
String username = authentication.getName();
//密码
String password = authentication.getCredentials().toString();
List<SimpleGrantedAuthority> roles = new ArrayList<>();
UserDetails userDetails = userDetailsService.loadUserByUsername(username);
if (userDetails == null) {
throw new UsernameNotFoundException("用户名/密码无效");
}
UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(username, password, roles);
token.setDetails(userDetails);
return token;
}
@Override
public boolean supports(Class<?> authentication) {
return (UsernamePasswordAuthenticationToken.class
.isAssignableFrom(authentication));
}
}
3. PasswordEncoder
Spring Security提供了很多加密方式,MD5、SHA、BCrypt等,官方推荐使用BCrypt,好处就不在这说了。自己百度下吧。提供的支持类就是BCryptPasswordEncoder
。使用方式简单,直接初始化。注入就可以用了。两个方法加密、解密。
PasswordEncoder
/**
* Encode the raw password. Generally, a good encoding algorithm applies a SHA-1 or
* greater hash combined with an 8-byte or greater randomly generated salt.
*/
String encode(CharSequence rawPassword);
/**
* Verify the encoded password obtained from storage matches the submitted raw
* password after it too is encoded. Returns true if the passwords match, false if
* they do not. The stored password itself is never decoded.
*
* @param rawPassword the raw password to encode and match
* @param encodedPassword the encoded password from storage to compare with
* @return true if the raw password, after encoding, matches the encoded password from
* storage
*/
boolean matches(CharSequence rawPassword, String encodedPassword);