最終效果
1、實(shí)現(xiàn)頁面訪問權(quán)限限制
2、用戶角色區(qū)分,并按照角色區(qū)分頁面權(quán)限
3、實(shí)現(xiàn)在數(shù)據(jù)庫中存儲(chǔ)用戶信息以及角色信息
4、自定義驗(yàn)證代碼
效果如下:
1、免驗(yàn)證頁面
2、登陸頁面
在用戶未登錄時(shí),訪問任意有權(quán)限要求的頁面都會(huì)自動(dòng)跳轉(zhuǎn)到登陸頁面。
3、需登陸才能查看的頁面
用戶登陸后,可以正常訪問頁面資源,同時(shí)可以正確顯示用戶登錄名:
4、用戶有角色區(qū)分,可以指定部分頁面只允許有相應(yīng)用戶角色的人使用
4.1、只有admin覺得用戶才能查看的頁面(權(quán)限不足)
4.2、只有admin覺得用戶才能查看的頁面(權(quán)限滿足)
以下具體說明實(shí)現(xiàn)步驟。
代碼實(shí)現(xiàn)
maven引入依賴
在pom.xml中引入spring security依賴
1
2
3
4
|
<dependency> <groupid>org.springframework.boot</groupid> <artifactid>spring-boot-starter-security</artifactid> </dependency> |
配置spring security
在spring中,配置和使用spring security,在不需要修改太多流程細(xì)節(jié)的情況下僅需聲明好攔截規(guī)則,同時(shí)自定義驗(yàn)證過程中的主要實(shí)現(xiàn)接口(用戶信息userdetails,用戶信息獲取服務(wù)userdetailsservice,驗(yàn)證工具authenticationprovider)即可。其余的流程將由spring自動(dòng)接管,非常方便。
啟動(dòng)配置
在項(xiàng)目包下添加websecurityconfigureradapter
的具體實(shí)現(xiàn)類,實(shí)現(xiàn)spring security的啟動(dòng)配置
代碼如下:
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
|
@configurable @enablewebsecurity @enableglobalmethodsecurity (prepostenabled = true ) //允許進(jìn)入頁面方法前檢驗(yàn) public class websecurityconfig extends websecurityconfigureradapter { @autowired private myauthenticationprovider provider; //自定義驗(yàn)證 @autowired private userdetailsservice userdetailsservice; //自定義用戶服務(wù) @autowired public void configauthentication(authenticationmanagerbuilder auth) throws exception{ } @override protected void configure(httpsecurity http) throws exception { http.authorizerequests() .antmatchers(staticparams.pathregx.noauth, staticparams.pathregx.css,staticparams.pathregx.js,staticparams.pathregx.img).permitall() //無需訪問權(quán)限 .antmatchers(staticparams.pathregx.authadmin).hasauthority(staticparams.userrole.role_admin) //admin角色訪問權(quán)限 .antmatchers(staticparams.pathregx.authuser).hasauthority(staticparams.userrole.role_user) //user角色訪問權(quán)限 .anyrequest() //all others request authentication .authenticated() .and() .formlogin().loginpage( "/login" ).permitall() .and() .logout().permitall(); } @autowired public void configureglobal(authenticationmanagerbuilder auth) throws exception { //將驗(yàn)證過程交給自定義驗(yàn)證工具 auth.authenticationprovider(provider); } |
url攔截配置
url攔截配置可以在上一小節(jié)的websecurityconfig 中配置,但是此方法適用于大方向上的配置,具體的特殊路徑也可以在@controller的注解中具體配置。
如下:
1
2
3
4
5
6
|
@responsebody @preauthorize ( "hasauthority('" +staticparams.userrole.role_admin+ "')" ) //這里可以指定特定角色的用戶訪問權(quán)限 @requestmapping (value = "adminrequire" , method = requestmethod.get) public string adminrequire(){ return "hello from web but you should be admin" ; } |
用戶、角色表
在本文例子中用戶和角色可以有一對(duì)多的關(guān)系因此可以將用戶和角色分成兩張表。有些例子將用戶和權(quán)限寫在同一張表上也是可以的。
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
58
59
60
61
62
63
64
65
66
67
68
69
70
71
|
/*用戶表*/ @entity @table(name = "user") public class systemuser { @id @column(name = "id") @generatedvalue(strategy = generationtype.auto) private long id; private string username; private string password; public systemuser(){} public systemuser(systemuser user){ this.username = user.getusername(); this.password = user.getpassword(); this.id = user.getid(); } public long getid() { return id; } public void setid(long id) { this.id = id; } public string getusername() { return username; } public void setusername(string username) { this.username = username; } public string getpassword() { return password; } public void setpassword(string password) { this.password = password; } } /*角色表*/ @entity @table (name = "user_role" ) public class userrole { @id @column (name = "id" ) @generatedvalue (strategy = generationtype.auto) private long id; private string role; private long userid; public long getid() { return id; } public void setid( long id) { this .id = id; } public string getrole() { return role; } public void setrole(string role) { this .role = role; } public long getuserid() { return userid; } public void setuserid( long userid) { this .userid = userid; } } |
自定義驗(yàn)證
在spring boot的spring security的教程中默認(rèn)的用戶名、密碼、權(quán)限是在代碼中指定的
1
2
3
4
5
6
|
@autowired public void configureglobal(authenticationmanagerbuilder auth) throws exception { auth .inmemoryauthentication() .withuser( "user" ).password( "password" ).roles( "user" ); } |
這顯然是不符合應(yīng)用需求的,所以我們需要提供自定義的authenticationprovider,并在上邊代碼中替換即可。在此之前,我們應(yīng)該重寫獲取用戶user和權(quán)限的方法。通過查詢相關(guān)資料和api,方法提供如下:
自定義userdetails
userdetails代表了spring security的用戶認(rèn)證實(shí)體,帶有用戶名、密碼、權(quán)限列表、過期特性等性質(zhì),可以自己聲明類實(shí)現(xiàn)userdetails接口,如果不想自己聲明,也可以用springsecurity的默認(rèn)實(shí)現(xiàn)org.springframework.security.core.userdetails.user 本文例子中采用自定義類:
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
|
public class myuserdetails extends systemuser implements userdetails{ private list<userrole> roles; public myuserdetails(systemuser user, list<userrole> roles){ super (user); this .roles = roles; } @override public collection<? extends grantedauthority> getauthorities() { if (roles == null || roles.size() < 1 ){ return authorityutils.commaseparatedstringtoauthoritylist( "" ); } stringbuilder commabuilder = new stringbuilder(); for (userrole role : roles){ commabuilder.append(role.getrole()).append( "," ); } string authorities = commabuilder.substring( 0 ,commabuilder.length()- 1 ); return authorityutils.commaseparatedstringtoauthoritylist(authorities); } @override public string getpassword() { return super .getpassword(); } @override public string getusername() { return super .getusername(); } @override public boolean isaccountnonexpired() { return true ; } @override public boolean isaccountnonlocked() { return true ; } @override public boolean iscredentialsnonexpired() { return true ; } @override public boolean isenabled() { return true ; } } |
自定義userdetailsservice
userdetailsservice提供了獲取userdetails的方式,只要實(shí)現(xiàn)userdetailsservice接口即可,最終生成用戶和權(quán)限共同組成的userdetails,在這里就可以實(shí)現(xiàn)從自定義的數(shù)據(jù)源中獲取用戶信息了:
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
|
@service ( "myuserdetailsimpl" ) public class myuserdetailsservice implements userdetailsservice { @resource (name = "systemuserserviceimpl" ) private systemuserservice systemuserservice; @resource (name = "userroleserviceimpl" ) private userroleservice userroleservice; @override public userdetails loaduserbyusername(string username) throws usernamenotfoundexception { systemuser user; try { user = systemuserservice.findbyname(username); } catch (exception e) { throw new usernamenotfoundexception( "user select fail" ); } if (user == null ){ throw new usernamenotfoundexception( "no user found" ); } else { try { list<userrole> roles = userroleservice.getrolebyuser(user); return new myuserdetails(user, roles); } catch (exception e) { throw new usernamenotfoundexception( "user role select fail" ); } } } } |
自定義authenticationprovider
authenticationprovider 提供用戶userdetails的具體驗(yàn)證方式,在這里可以自定義用戶密碼的加密、驗(yàn)證方式等等。因?yàn)椴┪闹饕v的是如何引入spring security和如何自定義驗(yàn)證代碼,所以這里為了簡(jiǎn)便,我直接采用明文比較方式:
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
|
@component public class myauthenticationprovider implements authenticationprovider { @autowired private myuserdetailsservice userservice; /** * 自定義驗(yàn)證方式 */ @override public authentication authenticate(authentication authentication) throws authenticationexception { string username = authentication.getname(); string password = (string) authentication.getcredentials(); myuserdetails user = (myuserdetails) userservice.loaduserbyusername(username); if (user == null ){ throw new badcredentialsexception( "username not found." ); } //加密過程在這里體現(xiàn) if (!password.equals(user.getpassword())) { throw new badcredentialsexception( "wrong password." ); } collection<? extends grantedauthority> authorities = user.getauthorities(); return new usernamepasswordauthenticationtoken(user, password, authorities); } @override public boolean supports( class <?> arg0) { return true ; } } |
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持服務(wù)器之家。
原文鏈接:http://blog.csdn.net/tzdwsy/article/details/50738043