Spring Security(二)
Spring Security(二)
注:凡是源码部分,我已经把英文注释去掉了,有兴趣的同学可以在自己项目里进去看看。😃
定义用户认证逻辑
用户登录成功后,用户的信息会被 Security 封装在一个接口里(“UserDetailsService”)
UserDetailsService 源码:
public interface UserDetailsService { // UserDetails 封装的用户信息接口 UserDetails loadUserByUsername(String username) throws UsernameNotFoundException; }
处理密码加密解密
Spring Security 处理登录密码的是 PasswordEncoder 接口。
PasswordEncoder 源码:
public interface PasswordEncoder { // 用来把用户登录时传入的密码进行加密处理 String encode(CharSequence rawPassword); // 用来判断加密后的密码和用户传入的代码是否匹配 boolean matches(CharSequence rawPassword, String encodedPassword); }
Security 为 PasswordEncoder 接口提供了默认的实现 BCryptPasswordEncoder ,在项目中配置上密码加解密如下:
@Configuration
public class BrowserSecurityConfig extends WebSecurityConfigurerAdapter {
@Bean
public PasswordEncoder passwordEncoder() {
// Security 默认实现
return new BCryptPasswordEncoder();
}
@Override
protected void configure(HttpSecurity http) throws Exception {
// 启用表单登陆
http.formLogin()
.and()
// 对请求做授权
.authorizeRequests()
// 任何请求
.anyRequest()
// 都需要身份认证
.authenticated();
}
}
配置 UserDetailService 接口实现:
@Configuration
public class MyUserDetailsService implements UserDetailsService {
private static final Logger log = LoggerFactory.getLogger(MyUserDetailsService.class);
@Autowired
private PasswordEncoder passwordEncoder;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
log.info("登录用户名 ={}", username);
// 根据用户名查询用户信息(此处省略与数据库交互逻辑)
// 下面的“User”对象是Security的,它实现了UserDetailsService接口
List<GrantedAuthority> grantedAuthorities =
AuthorityUtils.commaSeparatedStringToAuthorityList("admin");
// 根据查找到的用户信息判断用户是否被冻结
String encode = passwordEncoder.encode("123456");
log.info("加密后的密码 ={}", encode);
return new User(username, encode,
true, true, true, true, grantedAuthorities);
}
}
登录后,日志如下:
2019-01-10 01:22:10.946 INFO 6572 --- [nio-8081-exec-3] c.i.s.browser.MyUserDetailsService : 登录用户名 =root
2019-01-10 01:22:11.074 INFO 6572 --- [nio-8081-exec-3] c.i.s.browser.MyUserDetailsService : 加密后的密码 =$2a$10$8NCzA8f.T9vLijKnrI9BKOKVB53FB4esFG1QlaBT1Fmh2I5ITjRGm
由此可见,Security 默认的加解密接口实现中的密码加密并不是我们所熟悉的 MD5 ,如果想使用 MD5 加密,可自定义一个 PasswordEncoder 接口的实现类,如下:
/**
* 自定义 PasswordEncoder 接口实现
*/
public class MyPasswordEncoder implements PasswordEncoder {
@Override
public String encode(CharSequence rawPassword) {
String pwd = rawPassword.toString();
return DigestUtil.md5Hex(pwd);
}
@Override
public boolean matches(CharSequence rawPassword, String encodedPassword) {
return this.encode(rawPassword).equalsIgnoreCase(encodedPassword);
}
}
@Configuration
public class BrowserSecurityConfig extends WebSecurityConfigurerAdapter {
@Bean
public PasswordEncoder passwordEncoder() {
// Security 自定义实现
return new MyPasswordEncoder();
}
@Override
protected void configure(HttpSecurity http) throws Exception {
// 启用表单登陆
http.formLogin()
.and()
// 对请求做授权
.authorizeRequests()
// 任何请求
.anyRequest()
// 都需要身份认证
.authenticated();
}
}