SpringSecurity-7-自定義AuthenticationProvider實(shí)現(xiàn)圖形驗(yàn)證碼

SpringSecurity-7-自定義AuthenticationProvider實(shí)現(xiàn)圖形驗(yàn)證碼

上一章節(jié)我們介紹了如何使用過(guò)濾器(Filter)實(shí)現(xiàn)圖形驗(yàn)證咏窿,這是屬于Servlet層面抹估,比較簡(jiǎn)單容易理解。那么這次我們介紹SpringSecurity提供的另一種比較高端的實(shí)現(xiàn)圖形化驗(yàn)證碼净响,這就是AuthenticationProvider自定義認(rèn)證。

認(rèn)證流程

我們?cè)?/p>

其中介紹了系統(tǒng)的用戶信息喳瓣,保存在SpringSecurity的主體(Principal)中馋贤。主體中包含了所有經(jīng)過(guò)驗(yàn)證用戶的權(quán)限,詳細(xì)信息等內(nèi)容畏陕。在SpringSecurity中將其封裝放在Authentication中配乓,代碼如下

????public?interface?Authentication?extends?Principal,?Serializable?{
????????/**
?????????*?獲取用戶權(quán)限
?????????*?@return?????????*/
????????Collection<??extends?GrantedAuthority>?getAuthorities();
????????/**
?????????*?獲取用于的憑證,用戶密碼
?????????*?@return?????????*/
????????Object?getCredentials();
????????/**
?????????*?用戶的詳細(xì)信息
?????????*?@return?????????*/
????????Object?getDetails();
????????/**
?????????*?用戶憑證惠毁,一般為用戶名
?????????*?@return?????????*/
????????Object?getPrincipal();
????????/**
?????????*?用戶驗(yàn)證是否成功
?????????*?@return?????????*/
????????boolean?isAuthenticated();
????????void?setAuthenticated(boolean?isAuthenticated)?throws?IllegalArgumentException;
????}

說(shuō)明:

  • Authentication中包含主體權(quán)限列表犹芹,主體憑據(jù),主體的詳細(xì)信息鞠绰,及是否驗(yàn)證成功等腰埂。
  • AuthenticationProvider被SpringSecurity定義為一個(gè)驗(yàn)證過(guò)程
  • ProviderManager管理多個(gè)AuthenticationProvider

UsernamePasswordAuthenticationFilter

我們查看UsernamePasswordAuthenticationFilter類發(fā)現(xiàn)設(shè)置用戶信息的方法setDetails方法

從源碼我們可以看出authenticationDetailsSource是由AbstractAuthenticationProcessingFilter提供的AbstractAuthenticationProcessingFilter部分源碼如下

public?abstract?class?AbstractAuthenticationProcessingFilter?extends?GenericFilterBean
??????implements?ApplicationEventPublisherAware,?MessageSourceAware?{

???protected?ApplicationEventPublisher?eventPublisher;

???protected?AuthenticationDetailsSource<HttpServletRequest,??>?authenticationDetailsSource?=?new?WebAuthenticationDetailsSource();
?????...
???}

WebAuthenticationDetailsSource

在UsernamePasswordAuthenticationFilter中使用的AuthenticationDetailsSource是一個(gè)標(biāo)準(zhǔn)的Web認(rèn)證 源,攜帶的是用戶的sessionId和IP地址蜈膨。源碼如圖所示

自定義WebAuthenticationDetails

有了HttpServletRequest之后屿笼,一切都將變得非常順暢牺荠。基于圖形驗(yàn)證碼的場(chǎng)景刁卜,我們可以繼承 WebAuthenticationDetails志电,并擴(kuò)展需要的信息。因此我們可以自定義WebAuthenticationDetails存儲(chǔ)額外信息蛔趴。

/**
?*自定義WebAuthenticationDetails存儲(chǔ)額外的圖形驗(yàn)證信息?*/
public?class?ImageCodeWebAuthenticationDetails?extends?WebAuthenticationDetails?{
????/**
?????*?圖形信息是否驗(yàn)證成功?????*/
????private?boolean?imageCodeIsRight;

????public?boolean?getImageCodeIsRight(){
????????return?imageCodeIsRight;
????}
????public?ImageCodeWebAuthenticationDetails(HttpServletRequest?request)?{
????????super(request);
????????//?先獲取seesion中的驗(yàn)證碼
????????HttpSession?session?=?request.getSession();
????????String?sessionCode?=?(String)?session.getAttribute(CaptchaController.SESSION_KEY);
????????//?獲取用戶輸入的驗(yàn)證碼
????????String?inpuCode?=?request.getParameter("code");
????????if(!StringUtils.isEmpty(inpuCode)){
????????????//清除驗(yàn)證碼挑辆,不論驗(yàn)證成功還是失敗,都需要清除驗(yàn)證碼孝情,并且在驗(yàn)證失敗的時(shí)候需要刷新驗(yàn)證碼
????????????session.removeAttribute("code");
????????????if(!StringUtils.isEmpty(sessionCode)&&?inpuCode.equalsIgnoreCase(sessionCode)?){
????????????????this.imageCodeIsRight=true;
????????????}
????????}

????}
}

自定義的AuthenticationDetailsSource鱼蝉。

@Component("imageCodeWebAuthenticationDetailsSource")
public?class?ImageCodeWebAuthenticationDetailsSource?implements?AuthenticationDetailsSource<HttpServletRequest,?WebAuthenticationDetails>?{
????@Override
????public?ImageCodeWebAuthenticationDetails?buildDetails(HttpServletRequest?context)?{
????????return?new?ImageCodeWebAuthenticationDetails(context);
????}
}

自定義AuthenticationProvider。

@Component("imageCodeAuthenticationProvider")
public?class?ImageCodeAuthenticationProvider?extends?DaoAuthenticationProvider?{

????public?ImageCodeAuthenticationProvider(UserDetailsService?userDetailsService,?PasswordEncoder?passwordEncoder)?{
????????this.setUserDetailsService(userDetailsService);
????????this.setPasswordEncoder(passwordEncoder);

????}

????@Override
????protected?void?additionalAuthenticationChecks(UserDetails?userDetails,?UsernamePasswordAuthenticationToken?authentication)?throws?AuthenticationException?{
????????//獲取詳細(xì)信息
????????ImageCodeWebAuthenticationDetails??details?=?(ImageCodeWebAuthenticationDetails)authentication.getDetails();
????????//如果驗(yàn)證碼不正確箫荡,拋出異常
????????if(!details.getImageCodeIsRight()){
????????????throw?new?ValidateCodeException("驗(yàn)證碼輸入錯(cuò)誤");
????????}
????????super.additionalAuthenticationChecks(userDetails,?authentication);
????}

}

修改配置類

想要應(yīng)用自定義的 AuthenticationProvider 和 AuthenticationDetailsSource魁亦,還需在LearnSrpingSecurity中完成剩余的配置。

/**
?*?安全配置類?*/
@EnableWebSecurity
public?class?LearnSrpingSecurity?extends?WebSecurityConfigurerAdapter?{

????@Autowired
????@Qualifier("imageCodeWebAuthenticationDetailsSource")
????private?AuthenticationDetailsSource<HttpServletRequest,WebAuthenticationDetails>?imageCodeWebAuthenticationDetailsSource;

????@Autowired
????@Qualifier("imageCodeAuthenticationProvider")
????private?AuthenticationProvider?imageCodeAuthenticationProvider;
????/**
?????*?認(rèn)證管理器
?????*?1.認(rèn)證信息提供方式(用戶名羔挡、密碼洁奈、當(dāng)前用戶的資源權(quán)限)
?????*?2.可采用內(nèi)存存儲(chǔ)方式,也可能采用數(shù)據(jù)庫(kù)方式等
?????*?@param?auth
?????*?@throws?Exception?????*/
????@Override
????protected?void?configure(AuthenticationManagerBuilder?auth)?throws?Exception?{
????????//super.configure(auth);
????????auth.authenticationProvider(imageCodeAuthenticationProvider);
????}
????/**
?????*?資源權(quán)限配置(過(guò)濾器鏈):
?????*?1绞灼、被攔截的資源
?????*?2利术、資源所對(duì)應(yīng)的角色權(quán)限
?????* 3、定義認(rèn)證方式:httpBasic 低矮、httpForm
?????*?4印叁、定制登錄頁(yè)面、登錄請(qǐng)求地址军掂、錯(cuò)誤處理方式
?????*?5轮蜕、自定義?spring?security?過(guò)濾器
?????*?@param?http
?????*?@throws?Exception?????*/
????@Override
????protected?void?configure(HttpSecurity?http)?throws?Exception?{

????????http.csrf().disable()?//禁用跨站csrf攻擊防御,后面的章節(jié)會(huì)專門(mén)講解
????????????????.formLogin()
????????????????.authenticationDetailsSource(imageCodeWebAuthenticationDetailsSource)
????????????????.loginPage("/login/page")//一旦用戶的請(qǐng)求沒(méi)有權(quán)限就跳轉(zhuǎn)到這個(gè)頁(yè)面
????????????????.loginProcessingUrl("/login/form")//登錄表單form中action的地址蝗锥,也就是處理認(rèn)證請(qǐng)求的路徑
????????????????.usernameParameter("username")///登錄表單form中用戶名輸入框input的name名跃洛,不修改的話默認(rèn)是username
????????????????.passwordParameter("password")//form中密碼輸入框input的name名,不修改的話默認(rèn)是password
????????????????//.defaultSuccessUrl("/syslog")//登錄認(rèn)證成功后默認(rèn)轉(zhuǎn)跳的路徑
????????????????//.failureHandler(failureHandler)
????????????????.and()
????????????????.authorizeRequests()
????????????????.antMatchers("/login/page","/code/image").permitAll()//不需要通過(guò)登錄驗(yàn)證就可以被訪問(wèn)的資源路徑
????????????????.anyRequest().authenticated();
????}
}

主要修改如圖

測(cè)試

我們使用瀏覽器瀏覽http://localhost:8888玛追,輸入錯(cuò)誤的驗(yàn)證碼税课,結(jié)果為

如果您覺(jué)得本文不錯(cuò),歡迎關(guān)注,點(diǎn)贊,收藏支持痊剖,您的關(guān)注是我堅(jiān)持的動(dòng)力韩玩!

公眾號(hào)? springboot葵花寶典
主要分享JAVA技術(shù),主要包含SpringBoot陆馁、SpingCloud找颓、Docker、中間件等技術(shù)叮贩,以及Github開(kāi)源項(xiàng)目

原創(chuàng)不易击狮,轉(zhuǎn)載請(qǐng)注明出處佛析,感謝支持!如果本文對(duì)您有用彪蓬,歡迎轉(zhuǎn)發(fā)分享寸莫!

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市档冬,隨后出現(xiàn)的幾起案子膘茎,更是在濱河造成了極大的恐慌,老刑警劉巖酷誓,帶你破解...
    沈念sama閱讀 219,110評(píng)論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件披坏,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡盐数,警方通過(guò)查閱死者的電腦和手機(jī)棒拂,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,443評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)玫氢,“玉大人帚屉,你說(shuō)我怎么就攤上這事⊙浚” “怎么了涮阔?”我有些...
    開(kāi)封第一講書(shū)人閱讀 165,474評(píng)論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)灰殴。 經(jīng)常有香客問(wèn)我,道長(zhǎng)掰邢,這世上最難降的妖魔是什么牺陶? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,881評(píng)論 1 295
  • 正文 為了忘掉前任,我火速辦了婚禮辣之,結(jié)果婚禮上掰伸,老公的妹妹穿的比我還像新娘。我一直安慰自己怀估,他們只是感情好狮鸭,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,902評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著多搀,像睡著了一般歧蕉。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上康铭,一...
    開(kāi)封第一講書(shū)人閱讀 51,698評(píng)論 1 305
  • 那天惯退,我揣著相機(jī)與錄音,去河邊找鬼从藤。 笑死催跪,一個(gè)胖子當(dāng)著我的面吹牛锁蠕,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播懊蒸,決...
    沈念sama閱讀 40,418評(píng)論 3 419
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼荣倾,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了骑丸?” 一聲冷哼從身側(cè)響起舌仍,我...
    開(kāi)封第一講書(shū)人閱讀 39,332評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎者娱,沒(méi)想到半個(gè)月后抡笼,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,796評(píng)論 1 316
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡黄鳍,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,968評(píng)論 3 337
  • 正文 我和宋清朗相戀三年推姻,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片框沟。...
    茶點(diǎn)故事閱讀 40,110評(píng)論 1 351
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡藏古,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出忍燥,到底是詐尸還是另有隱情拧晕,我是刑警寧澤,帶...
    沈念sama閱讀 35,792評(píng)論 5 346
  • 正文 年R本政府宣布梅垄,位于F島的核電站厂捞,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏队丝。R本人自食惡果不足惜靡馁,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,455評(píng)論 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望机久。 院中可真熱鬧臭墨,春花似錦、人聲如沸膘盖。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,003評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)侠畔。三九已至结缚,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間软棺,已是汗流浹背掺冠。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,130評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人德崭。 一個(gè)月前我還...
    沈念sama閱讀 48,348評(píng)論 3 373
  • 正文 我出身青樓斥黑,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親眉厨。 傳聞我的和親對(duì)象是個(gè)殘疾皇子锌奴,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,047評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容