上一篇進行了最簡單的Spring Security的初始搭建,像用戶名和密碼都是固定的,這篇就來講講自定義用戶認證邏輯的實現,包括用戶信息的獲取,用戶密碼的校驗以及用戶密碼的加密校驗。
處理用戶信息獲取邏輯
源碼
- 用戶信息的獲取邏輯被封裝在UserDetailsService接口中,接口源碼:
public interface UserDetailsService {
UserDetails loadUserByUsername(String var1) throws UsernameNotFoundException;
}
- 作用:
根據用戶前端輸入的用戶名,會到存儲去讀取用戶信息封裝到返回值UserDetails中
,如果通過輸入的用戶名沒法找到數據庫中數據,則會拋出一個UsernameNotFoundException異常。
實操
- 我們可以創建自己的一個MyUserDetailsService,實現上面的接口,在loadUserByUsername方法中進行一個數據庫用戶信息的查詢返回。
@Component
public class MyUserDetailsService implements UserDetailsService {
private static final Logger LOGGER = LoggerFactory.getLogger(MyUserDetailsService.class);
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
LOGGER.info("登錄名:" + username);
// balabala,根據用戶名查找用戶密碼等信息返回(記得實際開發中是查庫得到的),第三個參數是用戶授權,後面再來詳細講
return new User(username, "123456", AuthorityUtils.commaSeparatedStringToAuthorityList("admin"));
}
}
- 效果:任意用戶名,密碼是
123456
才能進行登錄(假裝上面的密碼是數據庫中查到的!)
處理用戶校驗邏輯
源碼
- UserDetails接口解析,該接口用於返回用戶信息。
public interface UserDetails extends Serializable {
/**
* 用戶授權
*/
Collection<? extends GrantedAuthority> getAuthorities();
/**
* 用戶密碼
*/
String getPassword();
/**
* 用戶名
*/
String getUsername();
/**
* 以下四個方法可以自定義校驗邏輯,返回賬戶是否過期,true表示沒有過期
*/
boolean isAccountNonExpired();
/**
* 賬戶是否被鎖定或者凍結(一般可恢復),true表示沒被凍結
*/
boolean isAccountNonLocked();
/**
* 密碼是否過期,true表示沒有過期,可能有的網站需求密碼需要30天更換等
*/
boolean isCredentialsNonExpired();
/**
* 賬戶是否可用或者是否被刪(一般不可恢復),true表示可用
*/
boolean isEnabled();
}
實操
- 演示:以上四個boolean類型的方法只要有一個不爲true都不能夠通過登錄校驗
@Component
public class MyUserDetailsService implements UserDetailsService {
private static final Logger LOGGER = LoggerFactory.getLogger(MyUserDetailsService.class);
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
LOGGER.info("登錄名:" + username);
// balabala,根據用戶名查找用戶密碼等信息返回,第三個參數是用戶授權,後面再來詳細講
return new User(username, "123456",
true, true, true, false,
AuthorityUtils.commaSeparatedStringToAuthorityList("admin"));
}
}
處理密碼加密解碼
源碼
- PasswordEncoder接口解析,該接口用於密碼的加密解密
public interface PasswordEncoder {
/**
* 密碼加密,在註冊的時候,密碼插入數據庫之前需要你手動調用進行一個加密操作
*/
String encode(CharSequence var1);
/**
* 判斷加密的密碼和用戶傳過來的密碼是否匹配,該方法由security調用,匹配上了返回true,否則返回false
*/
boolean matches(CharSequence var1, String var2);
}
實操
- 配置上面接口的一個實例Bean。
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
- 記得我們的密碼是被加密的,所以數據庫中的密碼應該是被加密過的。
public class MyUserDetailsService implements UserDetailsService {
private static final Logger LOGGER = LoggerFactory.getLogger(MyUserDetailsService.class);
@Autowired
private PasswordEncoder passwordEncoder;
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
LOGGER.info("登錄名:" + username);
// balabala,根據用戶名查找用戶密碼等信息返回,第三個參數是用戶授權,後面再來詳細講
String password = passwordEncoder.encode("123456");
return new User(username, password,
true, true, true, false,
AuthorityUtils.commaSeparatedStringToAuthorityList("admin"));
}
}
- 演示,結果就是輸入正確密碼才能登陸,這裏我們發現對同一個密碼加密後的密文是不一樣的,這是BCryptPasswordEncoder提供的加密方式,當然你可以自己實現加密,比如MD5加密方式等。