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();
}
}