Spring Security自定義認(rèn)證器的實現(xiàn)代碼
在了解過Security的認(rèn)證器后,如果想自定義登陸,只要實現(xiàn)AuthenticationProvider還有對應(yīng)的Authentication就可以了
Authentication
首先要創(chuàng)建一個自定義的Authentication,Security提供了一個Authentication的子類AbstractAuthenticationToken
我們實現(xiàn)這個類可以了,他已經(jīng)實現(xiàn)了Authentication的一些方法
public class NamePassAuthenticationToken extends AbstractAuthenticationToken {
private static final long serialVersionUID = 520L;
private final Object principal;
private Object credentials;
//提供第一次進(jìn)來的構(gòu)造方法
public NamePassAuthenticationToken(Object principal, Object credentials) {
super((Collection)null);
this.principal = principal;
this.credentials = credentials;
this.setAuthenticated(false);
}
//提供填充Authentication的構(gòu)造方法
public NamePassAuthenticationToken(Object principal, Object credentials, Collection<? extends GrantedAuthority> authorities) {
super(authorities);
this.principal = principal;
this.credentials = credentials;
super.setAuthenticated(true);
}
@Override
public Object getCredentials() {
return this.credentials;
}
@Override
public Object getPrincipal() {
return this.principal;
}
@Override
public void setAuthenticated(boolean isAuthenticated) throws IllegalArgumentException {
if (isAuthenticated) {
throw new IllegalArgumentException("Cannot set this token to trusted - use constructor which takes a GrantedAuthority list instead");
} else {
super.setAuthenticated(false);
}
}
@Override
public void eraseCredentials() {
super.eraseCredentials();
this.credentials = null;
}
}這個類關(guān)鍵就是一個是認(rèn)證的,一個沒認(rèn)證的的構(gòu)造器
AuthenticationProvider
接著是AuthenticationProvider,需要實現(xiàn)他的authenticate方法
@Setter
public class NamePassAuthenticationProvider implements AuthenticationProvider {
private CustomUserDetailsService userDetailsService;
private PasswordEncoder passwordEncoder;
@Override
//具體認(rèn)證邏輯
public Authentication authenticate(Authentication authentication) {
NamePassAuthenticationToken authenticationToken = (NamePassAuthenticationToken) authentication;
String username = (String) authenticationToken.getPrincipal();
String password = (String) authenticationToken.getCredentials();
//讓具體認(rèn)證類去認(rèn)證
UserDetails user = userDetailsService.loadUserByUsername(username);
boolean matches = passwordEncoder.matches(password, user.getPassword());
if (!matches) {
ResMsg.throwException(AuthExceptionGroup.AUTH_ERROR);
}
//填充Authentication
NamePassAuthenticationToken authenticationResult = new NamePassAuthenticationToken(user, password, user.getAuthorities());
authenticationResult.setDetails(authenticationToken.getDetails());
return authenticationResult;
}
@Override
//指定具體的Authentication
//根據(jù)你指定的Authentication來找到具體的Provider
public boolean supports(Class<?> authentication) {
return NamePassAuthenticationToken.class.isAssignableFrom(authentication);
}
}SecurityConfigurerAdapter
接著就是填充配置了
@Component
public class NamePassAuthenticationSecurityConfig extends SecurityConfigurerAdapter<DefaultSecurityFilterChain, HttpSecurity> {
@Autowired
private CustomUserDetailsService customUserDetailsService;
@Autowired
private PasswordEncoder passwordEncoder;
@Override
public void configure(HttpSecurity http) {
//phonePass provider
NamePassAuthenticationProvider provider = new NamePassAuthenticationProvider();
provider.setUserDetailsService(customUserDetailsService);
provider.setPasswordEncoder(passwordEncoder);
http.authenticationProvider(provider);
}
}接下來就是導(dǎo)入配置了
通常都會有一個實現(xiàn)了WebSecurityConfigurerAdapter的配置類
把配置類注入進(jìn)來
@Autowired
private NamePassAuthenticationSecurityConfig namePassAuthenticationSecurityConfig;
protected void configure(HttpSecurity http) throws Exception {
http.apply(namePassAuthenticationSecurityConfig);
}UserDetailsService
UserDetailsService是具體的認(rèn)證實現(xiàn)類
這個類就非常熟悉了,只需要實現(xiàn)他的loadUserByUsername方法,就可以實現(xiàn)認(rèn)證了
@Override
public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
AuthmsViewAccount account = accountService.getAccount(username);
if(account == null) {
ResMsg.throwException(AUTH_ERROR);
}
if (account.getStatus() != 1) {
ResMsg.throwException(ACCOUNT_HAS_BANED);
}
String spliceStaffInfo = String.format("%d-%s",account.getAccountId(),account.getUsername());
//只要Collection<? extends GrantedAuthority> authorities
//這個參數(shù)不為空,就表明認(rèn)證通過,所以空集合也可以通過
return new User(spliceStaffInfo,account.getPassword(), AuthorityUtils.NO_AUTHORITIES);
}把認(rèn)證結(jié)果填充到上下文中
TokenFilter
如果結(jié)合了Token,那么需要從token中識別該用戶
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
String bearerToken = resolveToken(request);
if (bearerToken != null && !"".equals(bearerToken.trim()) && SecurityContextHolder.getContext().getAuthentication() == null) {
//從redis中獲取該用戶
NamePassAuthenticationToken namePassAuthenticationToken = authRedisHelper.get(bearerToken);
if(namePassAuthenticationToken != null) {
//將信息保存到上下文中
SecurityContextHolder.getContext().setAuthentication(namePassAuthenticationToken);
}
}
chain.doFilter(request, response);
}
private String resolveToken(HttpServletRequest request) {
String bearerToken = request.getHeader("Authorization");
if (StringUtils.hasText(bearerToken) && bearerToken.startsWith(TOKEN_PREFIX)) {
return bearerToken.substring(7);
}
return null;
}public NamePassAuthenticationToken get(String bearerToken){
String spliceStaffInfo = (String)redisRepository.get(formatKey(bearerToken));
if(spliceStaffInfo == null) {
return null;
}
return new NamePassAuthenticationToken(new AuthStaff(spliceStaffInfo),null,AuthorityUtils.NO_AUTHORITIES);
}登錄過程
在登錄的時候,就需要用到這個自定義的認(rèn)證器了
// 通過用戶名和密碼創(chuàng)建一個 Authentication 認(rèn)證對象,實現(xiàn)類為 NamePassAuthenticationToken NamePassAuthenticationToken authenticationToken = new NamePassAuthenticationToken(user.getUsername(), user.getPassword()); //通過 AuthenticationManager(默認(rèn)實現(xiàn)為ProviderManager)的authenticate方法驗證 Authentication 對象 //AuthenticationManager會通過你傳入的authenticationToken來找到具體的Provider Authentication authentication = authenticationManager.authenticate(authenticationToken); //填充用戶信息到secrity中的user里 User principal = (User) authentication.getPrincipal(); //獲取認(rèn)證后的信息 NamePassAuthenticationToken namePassAuthenticationToken = new NamePassAuthenticationToken(new AuthStaff(principal.getUsername()), null, authentication.getAuthorities()); // 生成token String bearerToken = IdUtil.fastSimpleUUID(); // 加載到reids authRedisHelper.set(bearerToken, namePassAuthenticationToken);
這樣就實現(xiàn)了自定義的認(rèn)證器了
到此這篇關(guān)于Spring Security自定義認(rèn)證器的文章就介紹到這了,更多相關(guān)Spring Security自定義認(rèn)證器內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Java?properties?和?yml?的區(qū)別解析
properties和yml都是Spring?Boot支持的兩種配置文件,它們可以看做Spring?Boot在不同時期的兩種“產(chǎn)品”,這篇文章主要介紹了Java?properties?和?yml?的區(qū)別,需要的朋友可以參考下2023-02-02
java編程實現(xiàn)求質(zhì)數(shù)與因式分解代碼分享
這篇文章主要介紹了Java編程實現(xiàn)求質(zhì)數(shù)與因式分解代碼分享,對二者的概念作了簡單介紹(多此一舉,哈哈),都是小學(xué)數(shù)學(xué)老師的任務(wù),然后分享了求解質(zhì)數(shù)和因式分解的Java代碼,具有一定借鑒價值,需要的朋友可以參考下。2017-12-12
mybatisplus報Invalid bound statement (not found)錯誤的解決方法
搭建項目時使用了mybatisplus,項目能夠正常啟動,但在調(diào)用mapper方法查詢數(shù)據(jù)庫時報Invalid bound statement (not found)錯誤。本文給大家分享解決方案,感興趣的朋友跟隨小編一起看看吧2020-08-08
Java里的static在Kotlin里如何實現(xiàn)
這篇文章主要介紹了Java里的static在Kotlin里如何實現(xiàn),文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-01-01
詳解Java是如何通過接口來創(chuàng)建代理并進(jìn)行http請求
今天給大家?guī)淼闹R是關(guān)于Java的,文章圍繞Java是如何通過接口來創(chuàng)建代理并進(jìn)行http請求展開,文中有非常詳細(xì)的介紹及代碼示例,需要的朋友可以參考下2021-06-06
SpringBoot Controller Post接口單元測試示例
今天小編就為大家分享一篇關(guān)于SpringBoot Controller Post接口單元測試示例,小編覺得內(nèi)容挺不錯的,現(xiàn)在分享給大家,具有很好的參考價值,需要的朋友一起跟隨小編來看看吧2018-12-12
SpringBoot+URule實現(xiàn)可視化規(guī)則引擎的方法示例
規(guī)則引擎其實是一種組件,它可以嵌入到程序當(dāng)中,將程序復(fù)雜的判斷規(guī)則從業(yè)務(wù)代碼中剝離出來,使得程序只需要關(guān)心自己的業(yè)務(wù),而不需要去進(jìn)行復(fù)雜的邏輯判斷,本文給大家介紹了SpringBoot+URule實現(xiàn)可視化規(guī)則引擎的方法示例,需要的朋友可以參考下2024-12-12
Java經(jīng)典設(shè)計模式之適配器模式原理與用法詳解
這篇文章主要介紹了Java經(jīng)典設(shè)計模式之適配器模式,簡單說明了適配器模式的概念、原理,并結(jié)合實例形式分析了java適配器模式的用法與相關(guān)注意事項,需要的朋友可以參考下2017-08-08
Apache?log4j2-RCE?漏洞復(fù)現(xiàn)及修復(fù)建議(CVE-2021-44228)
Apache?Log4j2是一款Java日志框架,大量應(yīng)用于業(yè)務(wù)系統(tǒng)開發(fā)。2021年11月24日,阿里云安全團(tuán)隊向Apache官方報告了Apache?Log4j2遠(yuǎn)程代碼執(zhí)行漏洞(CVE-2021-44228),本文給大家介紹Apache?log4j2-RCE?漏洞復(fù)現(xiàn)(CVE-2021-44228)的相關(guān)知識,感興趣的朋友一起看看吧2021-12-12

