国产片侵犯亲女视频播放_亚洲精品二区_在线免费国产视频_欧美精品一区二区三区在线_少妇久久久_在线观看av不卡

服務器之家:專注于服務器技術及軟件下載分享
分類導航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術|正則表達式|C/C++|IOS|C#|Swift|Android|VB|R語言|JavaScript|易語言|vb.net|

服務器之家 - 編程語言 - Java教程 - spring boot 集成 shiro 自定義密碼驗證 自定義freemarker標簽根據權限渲染不同頁面(推薦)

spring boot 集成 shiro 自定義密碼驗證 自定義freemarker標簽根據權限渲染不同頁面(推薦)

2021-06-19 10:30朋也 Java教程

這篇文章主要介紹了spring-boot 集成 shiro 自定義密碼驗證 自定義freemarker標簽根據權限渲染不同頁面,需要的朋友可以參考下

項目里一直用的是 spring-security ,不得不說,spring-security 真是東西太多了,學習難度太大(可能我比較菜),這篇博客來總結一下折騰shiro的成果,分享給大家,強烈推薦shiro,真心簡單 : )

引入依賴

?
1
2
3
4
5
<dependency>
 <groupid>org.apache.shiro</groupid>
 <artifactid>shiro-spring</artifactid>
 <version>1.4.0</version>
</dependency>

用戶,角色,權限

就是經典的rbac權限系統,下面簡單給一下實體類字段

adminuser.java

?
1
2
3
4
5
6
7
8
9
public class adminuser implements serializable {
 
 private static final long serialversionuid = 8264158018518861440l;
 private integer id;
 private string username;
 private string password;
 private integer roleid;
 // getter setter...
}

role.java

?
1
2
3
4
5
6
public class role implements serializable {
 private static final long serialversionuid = 7824693669858106664l;
 private integer id;
 private string name;
 // getter setter...
}

permission.java

?
1
2
3
4
5
6
7
8
9
public class permission implements serializable {
 private static final long serialversionuid = -2694960432845360318l;
 private integer id;
 private string name;
 private string value;
 // 權限的父節點的id
 private integer pid;
 // getter setter...
}

自定義realm

這貨就是查詢用戶的信息然后放在shiro的個人用戶對象的緩存里,shiro自己有一個session的對象(不是servlet里的session)作用就是后面用戶發起請求的時候拿來判斷有沒有權限

另一個作用是查詢一下用戶的信息,將用戶名,密碼組裝成一個 authenticationinfo 用于后面密碼校驗的

具體代碼如下

myshirorealm.java

 

?
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
@component
public class myshirorealm extends authorizingrealm {
 private logger log = loggerfactory.getlogger(myshirorealm.class);
 @autowired
 private adminuserservice adminuserservice;
 @autowired
 private roleservice roleservice;
 @autowired
 private permissionservice permissionservice;
 // 用戶權限配置
 @override
 protected authorizationinfo dogetauthorizationinfo(principalcollection principals) {
 //訪問@requirepermission注解的url時觸發
 simpleauthorizationinfo simpleauthorizationinfo = new simpleauthorizationinfo();
 adminuser adminuser = adminuserservice.selectbyusername(principals.tostring());
 //獲得用戶的角色,及權限進行綁定
 role role = roleservice.selectbyid(adminuser.getroleid());
 // 其實這里也可以不要權限那個類了,直接用角色這個類來做鑒權,
 // 不過角色包含很多的權限,已經算是大家約定的了,所以下面還是查詢權限然后放在authorizationinfo里
 simpleauthorizationinfo.addrole(role.getname());
 // 查詢權限
 list<permission> permissions = permissionservice.selectbyroleid(adminuser.getroleid());
 // 將權限具體值取出來組裝成一個權限string的集合
 list<string> permissionvalues = permissions.stream().map(permission::getvalue).collect(collectors.tolist());
 // 將權限的string集合添加進authorizationinfo里,后面請求鑒權有用
 simpleauthorizationinfo.addstringpermissions(permissionvalues);
 return simpleauthorizationinfo;
 }
 // 組裝用戶信息
 @override
 protected authenticationinfo dogetauthenticationinfo(authenticationtoken token) throws authenticationexception {
 string username = (string) token.getprincipal();
 log.info("用戶:{} 正在登錄...", username);
 adminuser adminuser = adminuserservice.selectbyusername(username);
 // 如果用戶不存在,則拋出未知用戶的異常
 if (adminuser == null) throw new unknownaccountexception();
 return new simpleauthenticationinfo(username, adminuser.getpassword(), getname());
 }
}

實現密碼校驗

shiro內置了幾個密碼校驗的類,有 md5credentialsmatcher sha1credentialsmatcher , 不過從1.1版本開始,都開始使用 hashedcredentialsmatcher 這個類了,通過配置加密規則來校驗

它們都實現了一個接口 credentialsmatcher 我這里也實現這個接口,實現一個自己的密碼校驗

說明一下,我這里用的加密方式是spring-security里的 bcryptpasswordencoder 作的加密,之所以用它,是因為同一個密碼被這貨加密后,密文都不一樣,下面是具體代碼

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
public class mycredentialsmatcher implements credentialsmatcher {
 
 @override
 public boolean docredentialsmatch(authenticationtoken token, authenticationinfo info) {
 // 大坑!!!!!!!!!!!!!!!!!!!
 // 明明token跟info兩個對象的里的credentials類型都是object,斷點看到的類型都是 char[]
 // 但是!!!!! token里轉成string要先強轉成 char[]
 // 而info里取credentials就可以直接使用 string.valueof() 轉成string
 // 醉了。。
 string rawpassword = string.valueof((char[]) token.getcredentials());
 string encodedpassword = string.valueof(info.getcredentials());
 return new bcryptpasswordencoder().matches(rawpassword, encodedpassword);
 }
}

配置shiro

因為項目是spring-boot開發的,shiro就用java代碼配置,不用xml配置, 具體配置如下

 

?
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
@configuration
public class shiroconfig {
 private logger log = loggerfactory.getlogger(shiroconfig.class);
 @autowired
 private myshirorealm myshirorealm;
 @bean
 public shirofilterfactorybean shirofilter(securitymanager securitymanager) {
 log.info("開始配置shirofilter...");
 shirofilterfactorybean shirofilterfactorybean = new shirofilterfactorybean();
 shirofilterfactorybean.setsecuritymanager(securitymanager);
 //攔截器.
 map<string,string> map = new hashmap<>();
 // 配置不會被攔截的鏈接 順序判斷 相關靜態資源
 map.put("/static/**", "anon");
 //配置退出 過濾器,其中的具體的退出代碼shiro已經替我們實現了
 map.put("/admin/logout", "logout");
 //<!-- 過濾鏈定義,從上向下順序執行,一般將/**放在最為下邊 -->:這是一個坑呢,一不小心代碼就不好使了;
 //<!-- authc:所有url都必須認證通過才可以訪問; anon:所有url都都可以匿名訪問-->
 map.put("/admin/**", "authc");
 // 如果不設置默認會自動尋找web工程根目錄下的"/login.jsp"頁面
 shirofilterfactorybean.setloginurl("/adminlogin");
 // 登錄成功后要跳轉的鏈接
 shirofilterfactorybean.setsuccessurl("/admin/index");
 //未授權界面;
 shirofilterfactorybean.setunauthorizedurl("/error");
 shirofilterfactorybean.setfilterchaindefinitionmap(map);
 return shirofilterfactorybean;
 }
 // 配置加密方式
 // 配置了一下,這貨就是驗證不過,,改成手動驗證算了,以后換加密方式也方便
 @bean
 public mycredentialsmatcher mycredentialsmatcher() {
 return new mycredentialsmatcher();
 }
 // 安全管理器配置
 @bean
 public securitymanager securitymanager() {
 defaultwebsecuritymanager securitymanager = new defaultwebsecuritymanager();
 myshirorealm.setcredentialsmatcher(mycredentialsmatcher());
 securitymanager.setrealm(myshirorealm);
 return securitymanager;
 }
}

登錄

都配置好了,就可以發起登錄請求做測試了,一個簡單的表單即可,寫在controller里就行

 

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
@postmapping("/adminlogin")
public string adminlogin(string username, string password,
       @requestparam(defaultvalue = "0") boolean rememberme,
       redirectattributes redirectattributes) {
 try {
 // 添加用戶認證信息
 subject subject = securityutils.getsubject();
 if (!subject.isauthenticated()) {
  usernamepasswordtoken token = new usernamepasswordtoken(username, password, rememberme);
  //進行驗證,這里可以捕獲異常,然后返回對應信息
  subject.login(token);
 }
 } catch (authenticationexception e) {
 // e.printstacktrace();
 log.error(e.getmessage());
 redirectattributes.addflashattribute("error", "用戶名或密碼錯誤");
 redirectattributes.addflashattribute("username", username);
 return redirect("/adminlogin");
 }
 return redirect("/admin/index");
}

從上面代碼可以看出,記住我功能也直接都實現好了,只需要在組裝 usernamepasswordtoken 的時候,將記住我字段傳進去就可以了,值是 true, false, 如果是true,登錄成功后,shiro會在本地寫一個cookie

調用 subject.login(token); 方法后,它會去鑒權,期間會產生各種各樣的異常,有以下幾種,可以通過捕捉不同的異常然后提示頁面不同的錯誤信息,相當的方便呀,有木有

  • accountexception 帳戶異常
  • concurrentaccessexception 這個好像是并發異常
  • credentialsexception 密碼校驗異常
  • disabledaccountexception 帳戶被禁異常
  • excessiveattemptsexception 嘗試登錄次數過多異常
  • expiredcredentialsexception 認證信息過期異常
  • incorrectcredentialsexception 密碼不正確異常
  • lockedaccountexception 帳戶被鎖定異常
  • unknownaccountexception 未知帳戶異常
  • unsupportedtokenexception login(authenticationtoken) 這個方法只能接收 authenticationtoken 類的對象,如果傳的是其它的類,就拋這個異常

上面這么多異常,shiro在處理登錄的邏輯時,會自動的發出一些異常,當然你也可以手動去處理登錄流程,然后根據不同的問題拋出不同的異常,手動處理的地方就在自己寫的 myshirorealm 里的 dogetauthenticationinfo() 方法里,我在上面代碼里只處理了一個帳戶不存在時拋出了一個 unknownaccountexception 的異常,其實還可以加更多其它的異常,這個要看個人系統的需求來定了

到這里已經可以正常的實現登錄了,下面來說一些其它相關的功能的實現

自定freemarker標簽

開發項目肯定要用到頁面模板,我這里用的是 freemarker ,一個用戶登錄后,頁面可能要根據用戶的不同權限渲染不同的菜單,github上有個開源的庫,也是可以用的,不過我覺得那個太麻煩了,就自己實現了一個,幾行代碼就能搞定

shirotag.java

 

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@component
public class shirotag {
 // 判斷當前用戶是否已經登錄認證過
 public boolean isauthenticated(){
 return securityutils.getsubject().isauthenticated();
 }
 // 獲取當前用戶的用戶名
 public string getprincipal() {
 return (string) securityutils.getsubject().getprincipal();
 }
 // 判斷用戶是否有 xx 角色
 public boolean hasrole(string name) {
 return securityutils.getsubject().hasrole(name);
 }
 // 判斷用戶是否有 xx 權限
 public boolean haspermission(string name) {
 return !stringutils.isempty(name) && securityutils.getsubject().ispermitted(name);
 }
}

將這個類注冊到freemarker的全局變量里

freemarkerconfig.java

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
@configuration
public class freemarkerconfig {
 private logger log = loggerfactory.getlogger(freemarkerconfig.class);
 @autowired
 private shirotag shirotag;
 @postconstruct
 public void setsharedvariable() throws templatemodelexception {
 //注入全局配置到freemarker
 log.info("開始配置freemarker全局變量...");
 // shiro鑒權
 configuration.setsharedvariable("sec", shirotag);
 log.info("freemarker自定義標簽配置完成!");
 }
}

有了這些配置后,就可以在頁面里使用了,具體用法如下

?
1
2
3
4
5
6
7
8
<#if sec.haspermission("topic:list")>
 <li <#if page_tab=='topic'>class="active"</#if>>
 <a href="/admin/topic/list" rel="external nofollow" >
  <i class="fa fa-list"></i>
  <span>話題列表</span>
 </a>
 </li>
</#if>

加上這個后,在渲染頁面的時候,就會根據當前用戶是否有查看話題列表的權限,然后來渲染這個菜單

注解權限

有了上面freemarker標簽判斷是否有權限來渲染頁面,這樣做只能防君子,不能防小人,如果一個人知道后臺的某個訪問鏈接,但這個鏈接它是沒有權限訪問的,那他只要手動輸入這個鏈接就還是可以訪問的,所以這里還要在controller層加一套防御,具體配置如下

在shiroconfig里加上兩個bean

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
//加入注解的使用,不加入這個注解不生效
@bean
public authorizationattributesourceadvisor authorizationattributesourceadvisor(defaultwebsecuritymanager securitymanager) {
 authorizationattributesourceadvisor authorizationattributesourceadvisor = new authorizationattributesourceadvisor();
 authorizationattributesourceadvisor.setsecuritymanager(securitymanager);
 return authorizationattributesourceadvisor;
}
@bean
@conditionalonmissingbean
public defaultadvisorautoproxycreator defaultadvisorautoproxycreator() {
 defaultadvisorautoproxycreator defaultaap = new defaultadvisorautoproxycreator();
 defaultaap.setproxytargetclass(true);
 return defaultaap;
}

有了這兩個bean就可以用shiro的注解鑒權了,用法如下 @requirespermissions("topic:list")

 

?
1
2
3
4
5
6
7
8
9
10
11
@controller
@requestmapping("/admin/topic")
public class topicadmincontroller extends baseadmincontroller {
 
 @requirespermissions("topic:list")
 @getmapping("/list")
 public string list() {
 // todo
 return "admin/topic/list";
 }
}

shiro除了 @requirespermissions 注解外,還有其它幾個鑒權的注解

  • @requirespermissions
  • @requiresroles
  • @requiresuser
  • @requiresguest
  • @requiresauthentication

一般 @requirespermissions 就夠用了

總結

spring-boot 集成 shiro 到這就結束了,是不是網上能找到的教程里最全的!相比 spring-security 要簡單太多了,強烈推薦

原文鏈接:https://tomoya92.github.io/2018/12/05/spring-boot-shiro/

延伸 · 閱讀

精彩推薦
Weibo Article 1 Weibo Article 2 Weibo Article 3 Weibo Article 4 Weibo Article 5 Weibo Article 6 Weibo Article 7 Weibo Article 8 Weibo Article 9 Weibo Article 10 Weibo Article 11 Weibo Article 12 Weibo Article 13 Weibo Article 14 Weibo Article 15 Weibo Article 16 Weibo Article 17 Weibo Article 18 Weibo Article 19 Weibo Article 20 Weibo Article 21 Weibo Article 22 Weibo Article 23 Weibo Article 24 Weibo Article 25 Weibo Article 26 Weibo Article 27 Weibo Article 28 Weibo Article 29 Weibo Article 30 Weibo Article 31 Weibo Article 32 Weibo Article 33 Weibo Article 34 Weibo Article 35 Weibo Article 36 Weibo Article 37 Weibo Article 38 Weibo Article 39 Weibo Article 40
主站蜘蛛池模板: 精品久久av | 国产综合久久久 | 日日操天天操 | 国产一区二区三区免费在线观看 | 91在线视频导航 | 一级毛片在线播放 | 欧美精品 在线观看 | 玖玖国产精品视频 | 色天堂影院 | aaa视频网站 | 中国一级毛片 | www.欧美| 91偷拍精品一区二区三区 | 日本精a在线观看 | 亚洲一区中文字幕在线观看 | 国产中文一区 | 久久在线播放 | 亚洲人视频在线 | 成年人免费网站 | 一级黄色录像在线观看 | 欧美精品在线一区 | 国产欧美精品一区二区三区四区 | 91视频免费观看 | 亚洲色视频 | 久久精品国产精品青草 | 一级片网 | 女教师高潮叫床视频在线观看 | 一区二区久久 | 国产亚洲视频在线 | 精品久久久久久久人人人人传媒 | 中文字幕网站 | 日本视频中文字幕 | 中国一级毛片 | 美女久久久久 | 亚洲国产精品久久久久秋霞蜜臀 | 亚洲一区中文字幕在线观看 | 中文字幕第七页 | 日日操操| 久久www免费人成看片高清 | 国产高清在线精品一区二区三区 | 日韩精品一区二区三区中文字幕 |