我們系統(tǒng)中的認(rèn)證場(chǎng)景通常比較復(fù)雜,比如說(shuō)用戶(hù)被鎖定無(wú)法登錄,限制登錄ip等。而springsecuriy最基本的是基于用戶(hù)與密碼的形式進(jìn)行認(rèn)證,由此可知它的一套驗(yàn)證規(guī)范根本無(wú)法滿(mǎn)足業(yè)務(wù)需要,因此擴(kuò)展勢(shì)在必行。那么我們可以考慮自己定義filter添加至springsecurity的過(guò)濾器棧當(dāng)中,來(lái)實(shí)現(xiàn)我們自己的驗(yàn)證需要。
本例中,基于前篇的數(shù)據(jù)庫(kù)的student表來(lái)模擬一個(gè)簡(jiǎn)單的例子:當(dāng)student的jointime在當(dāng)天之后,那么才允許登錄
一、創(chuàng)建自己定義的filter
我們先在web包下創(chuàng)建好幾個(gè)包并定義如下幾個(gè)類(lèi)
customerauthfilter:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
|
package com.bdqn.lyrk.security.study.web.filter; import com.bdqn.lyrk.security.study.web.authentication.userjointimeauthentication; import org.springframework.security.authentication.authenticationmanager; import org.springframework.security.core.authentication; import org.springframework.security.core.authenticationexception; import org.springframework.security.web.authentication.abstractauthenticationprocessingfilter; import org.springframework.security.web.util.matcher.antpathrequestmatcher; import javax.servlet.servletexception; import javax.servlet.http.httpservletrequest; import javax.servlet.http.httpservletresponse; import java.io.ioexception; public class customerauthfilter extends abstractauthenticationprocessingfilter { private authenticationmanager authenticationmanager; public customerauthfilter(authenticationmanager authenticationmanager) { super ( new antpathrequestmatcher( "/login" , "post" )); this .authenticationmanager = authenticationmanager; } @override public authentication attemptauthentication(httpservletrequest request, httpservletresponse response) throws authenticationexception, ioexception, servletexception { string username = request.getparameter( "username" ); userjointimeauthentication usernamepasswordauthenticationtoken = new userjointimeauthentication(username); authentication authentication = this .authenticationmanager.authenticate(usernamepasswordauthenticationtoken); if (authentication != null ) { super .setcontinuechainbeforesuccessfulauthentication( true ); } return authentication; } } |
該類(lèi)繼承abstractauthenticationprocessingfilter,這個(gè)filter的作用是對(duì)最基本的用戶(hù)驗(yàn)證的處理,我們必須重寫(xiě)attemptauthentication方法。authentication接口表示授權(quán)接口,通常情況下業(yè)務(wù)認(rèn)證通過(guò)時(shí)會(huì)返回一個(gè)這個(gè)對(duì)象。super.setcontinuechainbeforesuccessfulauthentication(true) 設(shè)置成true的話(huà),會(huì)交給其他過(guò)濾器處理。
二、定義userjointimeauthentication
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
package com.bdqn.lyrk.security.study.web.authentication; import org.springframework.security.authentication.abstractauthenticationtoken; public class userjointimeauthentication extends abstractauthenticationtoken { private string username; public userjointimeauthentication(string username) { super ( null ); this .username = username; } @override public object getcredentials() { return null ; } @override public object getprincipal() { return username; } } |
自定義授權(quán)方式,在這里接收username的值處理,其中g(shù)etprincipal我們可以用來(lái)存放登錄名,getcredentials可以存放密碼,這些方法來(lái)自于authentication接口
三、定義authenticationprovider
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
|
package com.bdqn.lyrk.security.study.web.authentication; import com.bdqn.lyrk.security.study.app.pojo.student; import org.springframework.security.authentication.authenticationprovider; import org.springframework.security.core.authentication; import org.springframework.security.core.authenticationexception; import org.springframework.security.core.userdetails.userdetails; import org.springframework.security.core.userdetails.userdetailsservice; import java.util.date; /** * 基本的驗(yàn)證方式 * * @author chen.nie * @date 2018/6/12 **/ public class userjointimeauthenticationprovider implements authenticationprovider { private userdetailsservice userdetailsservice; public userjointimeauthenticationprovider(userdetailsservice userdetailsservice) { this .userdetailsservice = userdetailsservice; } /** * 認(rèn)證授權(quán),如果jointime在當(dāng)前時(shí)間之后則認(rèn)證通過(guò) * @param authentication * @return * @throws authenticationexception */ @override public authentication authenticate(authentication authentication) throws authenticationexception { string username = (string) authentication.getprincipal(); userdetails userdetails = this .userdetailsservice.loaduserbyusername(username); if (!(userdetails instanceof student)) { return null ; } student student = (student) userdetails; if (student.getjointime().after( new date())) return new userjointimeauthentication(username); return null ; } /** * 只處理userjointimeauthentication的認(rèn)證 * @param authentication * @return */ @override public boolean supports( class <?> authentication) { return authentication.getname().equals(userjointimeauthentication. class .getname()); } } |
authenticationmanager會(huì)委托authenticationprovider進(jìn)行授權(quán)處理,在這里我們需要重寫(xiě)support方法,該方法定義provider支持的授權(quán)對(duì)象,那么在這里我們是對(duì)userjointimeauthentication處理。
四、websecurityconfig
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
|
package com.bdqn.lyrk.security.study.app.config; import com.bdqn.lyrk.security.study.app.service.userservice; import com.bdqn.lyrk.security.study.web.authentication.userjointimeauthenticationprovider; import com.bdqn.lyrk.security.study.web.filter.customerauthfilter; import org.springframework.beans.factory.annotation.autowired; import org.springframework.security.config.annotation.authentication.builders.authenticationmanagerbuilder; import org.springframework.security.config.annotation.web.builders.httpsecurity; import org.springframework.security.config.annotation.web.builders.websecurity; import org.springframework.security.config.annotation.web.configuration.enablewebsecurity; import org.springframework.security.config.annotation.web.configuration.websecurityconfigureradapter; import org.springframework.security.web.authentication.usernamepasswordauthenticationfilter; /** * spring-security的相關(guān)配置 * * @author chen.nie * @date 2018/6/7 **/ @enablewebsecurity public class websecurityconfig extends websecurityconfigureradapter { @autowired private userservice userservice; @override protected void configure(httpsecurity http) throws exception { /* 1.配置靜態(tài)資源不進(jìn)行授權(quán)驗(yàn)證 2.登錄地址及跳轉(zhuǎn)過(guò)后的成功頁(yè)不需要驗(yàn)證 3.其余均進(jìn)行授權(quán)驗(yàn)證 */ http. authorizerequests().antmatchers( "/static/**" ).permitall(). and().authorizerequests().antmatchers( "/user/**" ).hasrole( "7022" ). and().authorizerequests().anyrequest().authenticated(). and().formlogin().loginpage( "/login" ).successforwardurl( "/toindex" ).permitall() .and().logout().logouturl( "/logout" ).invalidatehttpsession( true ).deletecookies().permitall() ; http.addfilterbefore( new customerauthfilter(authenticationmanager()), usernamepasswordauthenticationfilter. class ); } @override protected void configure(authenticationmanagerbuilder auth) throws exception { //設(shè)置自定義userservice auth.userdetailsservice(userservice); auth.authenticationprovider( new userjointimeauthenticationprovider(userservice)); } @override public void configure(websecurity web) throws exception { super .configure(web); } } |
在這里面我們通過(guò)httpsecurity的方法來(lái)添加我們自定義的filter,一定要注意先后順序。在authenticationmanagerbuilder當(dāng)中還需要添加我們剛才定義的authenticationprovider
啟動(dòng)成功后,我們將student表里的jointime值改為早于今天的時(shí)間,進(jìn)行登錄可以發(fā)現(xiàn):
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持服務(wù)器之家。
原文鏈接:https://www.cnblogs.com/niechen/p/9174096.html