1. 程式人生 > >(八) SpringBoot起飛之路-整合Shiro詳細教程(MyBatis、Thymeleaf)

(八) SpringBoot起飛之路-整合Shiro詳細教程(MyBatis、Thymeleaf)

![](https://user-gold-cdn.xitu.io/2020/7/13/17345dcb7e869d5d?w=900&h=383&f=png&s=44739) 興趣的朋友可以去了解一下前幾篇,你的贊就是對我最大的支援,感謝大家! (一) SpringBoot起飛之路-HelloWorld (二) SpringBoot起飛之路-入門原理分析 (三) SpringBoot起飛之路-YAML配置小結(入門必知必會) (四) SpringBoot起飛之路-靜態資源處理 (五) SpringBoot起飛之路-Thymeleaf模板引擎 (六) SpringBoot起飛之路-整合JdbcTemplate-Druid-MyBatis (七) SpringBoot起飛之路-整合SpringSecurity **說明:** - 這一篇的目的還是整合,也就是一個具體的實操體驗,原理性的沒涉及到,我本身也沒有深入研究過,就不獻醜了 - SpringBoot 起飛之路 系列文章的原始碼,均同步上傳到 github 了,有需要的小夥伴,隨意去 down - https://github.com/ideal-20/Springboot-Study-Code - 才疏學淺,就會點淺薄的知識,大家權當一篇工具文來看啦,不喜勿憤哈 ~ # (一) 初識 Shiro ## (1) 引言 許可權以及安全問題,雖然並不是一個影響到程式、專案執行的必須條件,但是卻是開發中的一項重要考慮因素,例如某些資源我們不想被訪問到或者我們某些方法想要滿足指定身份才可以訪問,我們可以使用 AOP 或者過濾器來實現要求,但是實際上,如果程式碼涉及的邏輯比較多以後,程式碼是極其繁瑣,冗餘的,而有很多開發框架,例如 Spring Security,Shiro,已經為我們提供了這種功能,我們只需要知道如何正確配置以及使用它了 ## (2) 基本介紹 官網:`http://shiro.apache.org/` **Apache Shiro™** is a powerful and easy-to-use Java security framework that performs authentication, authorization, cryptography, and session management. With Shiro’s easy-to-understand API, you can quickly and easily secure any application – from the smallest mobile applications to the largest web and enterprise applications. Apache Shiro™是一個功能強大且易於使用的Java安全框架,可執行身份驗證、授權、加密和會話管理。通過Shiro易於理解的API,您可以快速、輕鬆地保護任何應用程式——從最小的移動應用程式到最大的web和企業應用程式。 簡單梳理一下: - Shiro 和 Spring Security 性質是一樣的,都是一款許可權框架,用來保證應用的許可權安全問題 - Shiro 可執行身份驗證、授權、加密和會話管理,Web整合,快取等 - Shiro 不僅可以應用到 JavaEE 環境下,甚至 JavaSE 也可以 ## (3) 基本功能 這部分的內容,說實話,剛入門簡單掃兩眼就行了,只有你真的敲過一次程式碼了,你才大概對其中某些部分能有個印象,再繼續深入研究才可能有比較好的掌握 ### A:官方架構圖 ![](https://user-gold-cdn.xitu.io/2020/7/13/17345dcb870bac3e?w=495&h=257&f=png&s=29487) - Authentication:使用者認證就是指這個使用者身份是否合法,一般我們的使用者認證就是通過校驗使用者名稱密碼,來判斷使用者身份的合法性,確定身份合法後,使用者就可以訪問該系統 - Authorization:如果不同的使用者需要有不同等級的許可權,就涉及到使用者授權,使用者授權就是對使用者能訪問的資源,所能執行的操作進行控制,根據不同使用者角色或者對應不同許可權來劃分不同的許可權 - SessionManager:Shior 官網說其提供了一個完整的會話管理解決方案, 它的所會話可以是普通的Java SE環境, 也可以是Web環境,不過我有點思維定式了,還是用習慣的方式,這塊沒怎麼研究 - Cryptography:加密明文密碼, 保護資料安全 - WebSupport:字面意思,其對Web的支援, 使得其可以非常容易的整合到Web環境; - Caching:快取, 比如使用者登入後, 其使用者資訊, 擁有的角色、許可權不必每次去查,效率上會好一點 - Concurrency:Shiro 支援多執行緒應用的併發驗證,即,如在一個執行緒中開啟另一個執行緒,能把許可權自動傳過去 - Testing:沒什麼好說的,就是支援測試 - Run As:允許一個使用者假裝為另一個使用者(允許的條件下) 的身份進行訪問資源請求 - Remember Me:它也有,記住我這個功能 ### B:三大核心元件 Shiro框架中有三個核心元件:Subject ,SecurityManager和Realms ![](https://user-gold-cdn.xitu.io/2020/7/13/17345dcb933e4e2f?w=414&h=224&f=png&s=31282) 1. Subject 是一個安全術語,代表認證主體,一般來說可以簡單的理解為,當前操作的使用者,不過使用者這個概念實際上也不是很準確,因為 Subject 實際上不一定是人,也可以是一些例如第三方程序或者定時作業等等的事物,也就是理解為,當前同軟體互動的事物。 - 每一個Subject物件都必須被 SecurityManager 進行管理 2. Subject 接受 SecurityManager 的管理,因為 SecurityManager 管理所有使用者的安全操作,其內部引用了很多安全相關的元件,但是都不對外開放,開發人員更多的是使用 Subject 3. Realms 這個概念也是重要的,其可以理解為 Shiro 與 資料之間的溝通器與中間橋樑認證授權時,就會去此部分找一些內容,從本質上 Realm 就是一個經過了大量封裝的安全 Dao ## (4) 使用者|角色|許可權的概念 既然 Shiro 是一個安全許可權技術,簡單來說,就是對程式中被訪問的資源或者請求進行一定程度的控制,而如何劃分就涉及到這三個概念:使用者、角色、許可權 使用者(User):沒啥好說的,代表當前 Subject 認證主體,例如某些內容必須使用者登入後才可以訪問 角色(Role):這代表使用者擔任的角色,身份,一個角色可以有多個許可權,例如這一塊只有管理員可以訪問 許可權(Permission):也就是操作資源的具體的權利,例如對資料進行新增、修改、刪除、檢視操作 補充:其實可以簡單的理解,角色就是一些許可權的集合組成的,正是這一堆許可權已經將這個角色能做的事情限定死了,不用每次都說明這個角色可以做什麼 # (二) 靜態頁面匯入 And 頁面環境搭建 ## (1) 關於靜態頁面 ### A:頁面介紹 頁面是我自己臨時弄得,有需要的朋友可以去我 GitHub:ideal-20 下載原始碼,簡單說明一下這個頁面 做一個靜態頁面如果嫌麻煩,也可以單純的自己建立一些簡單的頁面,寫幾個標題文字,能體現出當前是哪個頁面就好了 我程式碼中用的這些頁面,就是拿開源的前端元件框架進行了一點的美化,然後方便講解一些功能,頁面模板主要是配合 Thymeleaf **1、目錄結構** ```java ├── index.html // 首頁 ├── images // 首頁圖片,僅美觀,無實際作用 ├── css ├── js ├── views // 總子頁面資料夾,許可權驗證的關鍵頁面 │ ├── login.html // 登入頁面 │ ├── success.html // 成功頁面 │ ├── unauthorized.html // 未授權頁面:此部分未授權的使用者訪問資源,跳轉到此頁面 │ ├── L-A // L-A 子頁面資料夾,下含 a b c 三個子頁面 │ │ ├── a.html │ │ ├── b.html │ │ ├── c.html | ├── L-B // L-B 子頁面資料夾,下含 a b c 三個子頁面 │ │ ├── a.html │ │ ├── b.html │ │ ├── c.html | ├── L-C // L-C 子頁面資料夾,下含 a b c 三個子頁面 │ │ ├── a.html │ │ ├── b.html │ │ ├── c.html ``` ### B:匯入到專案 主要就是把基本一些連結,引入什麼的先替換成 Thymeleaf 的標籤格式,這裡語法用的不是特別多,即使對於 Thymeleaf 不是很熟悉也是很容易看懂的,當然如果仍然感覺有點吃力,可以單純的做成 html,將就一下,或者去看一下我以前的文章哈,裡面有關於 Thymeleaf 入門的講解 css、image、js 放到 resources --> static 下 ,views 和 index.html 放到 resources --> templates下 ![](https://user-gold-cdn.xitu.io/2020/7/13/17345dcb7eaaa829?w=352&h=446&f=png&s=16175) ## (2) 環境搭建 ### A:引入依賴 這一部分引入也好,初始化專案的時候,勾選好自動生成也好,只要依賴正常匯入了即可 - 引入 Spring Security 模組 ```xml ``` 關鍵的依賴主要就是上面這個啟動器,但是還有一些就是常規或者補充的了,例如 **web、thymeleaf、devtools** 等等,還有一些例如 Mybatis 等我都放進來了,下面的依賴基本已經全了,具體講到某塊,具體再說 **thymeleaf-extras-shiro** 這個後面講解中會提到,是用來配合 Thymeleaf 整合 Shiro 的 ```xml ``` ### B:頁面跳轉 Controller 因為我們用了模板,頁面的跳轉就需要交給 Controller 了,很簡單,首先是首頁的,當然關於頁面這個就無所謂了,我隨便跳轉到了我的部落格,接著還有登入頁面、成功,未授權頁面的跳轉 有一個小 Tip 需要提一下,因為 L-A、L-B、L-C 資料夾下都有3個頁面 a.html 、b.html 、c.html,所以可以利用 @PathVariable 寫一個較為通用的跳轉方法 ```java @Controller public class PageController { @RequestMapping({"/", "index"}) public String index() { return "index"; } @RequestMapping("/about") public String toAboutPage() { return "redirect:http://www.ideal-20.cn"; } @RequestMapping("/toLoginPage") public String toLoginPage() { return "views/login"; } @RequestMapping("/levelA/{name}") public String toLevelAPage(@PathVariable("name") String name) { return "views/L-A/" + name; } @RequestMapping("/levelB/{name}") public String toLevelBPage(@PathVariable("name") String name) { return "views/L-B/" + name; } @RequestMapping("/levelC/{name}") public String toLevelCPage(@PathVariable("name") String name) { return "views/L-C/" + name; } @RequestMapping("/unauthorized") public String toUnauthorizedPage() { return "views/unauthorized"; } @RequestMapping("/success") public String toSuccessPage() { return "views/success"; } } ``` ### C:環境搭建最終效果 - 為了貼圖方便,我把頁面拉窄了一點 - 首頁右上角應該為登入的連結,這裡是因為,我執行的是已經寫好的程式碼,不登入頁面例如 L-A-a 等模組就顯示不出來,所以拿一個定義好的管理員身份登陸了 - 關於如何使其自動切換顯示登陸還是登入後資訊,在後面會講解 **1、首頁** ![](https://user-gold-cdn.xitu.io/2020/7/13/17345dcb7eccdd17?w=1061&h=887&f=png&s=161715) **2、子頁面** L-A、L-B、L-C 下的 a.html 、b.html 、c.html 都是一樣的,只是文字有一點變化 ![](https://user-gold-cdn.xitu.io/2020/7/13/17345dcb7f1502e6?w=1059&h=227&f=png&s=33391) **3、登陸頁面** ![](https://user-gold-cdn.xitu.io/2020/7/13/17345dcbb002ea13?w=500&h=407&f=png&s=10722) **4、成功及未授權頁面** 我截了個圖,把兩個頁面拼接到一起了,沒啥好說的,就是兩個很普通的H5頁面 ![](https://user-gold-cdn.xitu.io/2020/7/13/17345dcbb9b7de07?w=388&h=278&f=png&s=11399) # (三) 建立資料庫及實體 ## (1) 建立資料庫以及表 ```sql -- ---------------------------- -- Table structure for role -- ---------------------------- CREATE TABLE `role` ( `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '角色表主鍵', `role_name` varchar(32) DEFAULT NULL COMMENT '角色名稱', PRIMARY KEY (`id`) ); -- ---------------------------- -- Records of role -- ---------------------------- INSERT INTO `role` VALUES (1, 'SUPER_ADMIN'); INSERT INTO `role` VALUES (2, 'ADMIN'); INSERT INTO `role` VALUES (3, 'USER'); -- ---------------------------- -- Table structure for user -- ---------------------------- DROP TABLE IF EXISTS `user`; CREATE TABLE `user` ( `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '使用者主鍵', `username` varchar(32) NOT NULL COMMENT '使用者名稱', `password` varchar(32) NOT NULL COMMENT '密碼', `role_id` int(11) DEFAULT NULL COMMENT '與role角色表聯絡的外來鍵', PRIMARY KEY (`id`), CONSTRAINT `user_role_on_role_id` FOREIGN KEY (`role_id`) REFERENCES `role` (`id`) ); -- ---------------------------- -- Records of user -- ---------------------------- INSERT INTO `user` VALUES (1, 'BWH_Steven', '666666', 1); INSERT INTO `user` VALUES (2, 'admin', '666666', 2); INSERT INTO `user` VALUES (3, 'zhangsan', '666666', 3); -- ---------------------------- -- Table structure for permission -- ---------------------------- CREATE TABLE `permission` ( `id` int(11) NOT NULL AUTO_INCREMENT COMMENT '許可權表主鍵', `permission_name` varchar(50) NOT NULL COMMENT '許可權名', `role_id` int(11) DEFAULT NULL COMMENT '與role角色表聯絡的外來鍵', PRIMARY KEY (`id`), CONSTRAINT `permission_role_on_role_id` FOREIGN KEY (`role_id`) REFERENCES `role` (`id`) ); -- ---------------------------- -- Records of permission -- ---------------------------- INSERT INTO `permission` VALUES (1, 'user:*', 1); INSERT INTO `permission` VALUES (2, 'user:*', 2); INSERT INTO `permission` VALUES (3, 'user:queryAll', 3); ``` ## (2) 實體 在資料庫中角色表,在使用者表和許可權表分別是有一個外來鍵的概念,所以在實體中就寫成了引用的形式 角色類 ```java @Data @AllArgsConstructor @NoArgsConstructor @Getter @Setter public class Role { private int id; private String roleName; } ``` 使用者類,說明:由於我在其他模組下有一些同名的類,呼叫的時候經常會有一些誤會,所以就稍微改了下名字 --> UserPojo,這裡大家起 User 就 OK ```java @Data @AllArgsConstructor @NoArgsConstructor @Getter @Setter public class UserPojo { private int id; private String username; private String password; private Role role; } ``` 許可權類 ```java @Data @AllArgsConstructor @NoArgsConstructor @Getter @Setter public class Permission { private Integer id; private String permissionName; private Role role; } ``` # (四) 整合 MyBatis 今天要做的內容,實際上自己隨便模擬兩個資料也是可以的,不過為了貼近現實,還是引入了 Mybaits ## (1) 引入依賴及進行配置 先引入 MyBatis 依賴,還有驅動依賴 ```xml ``` 連線池啥的就不折騰了,想自己換就自己配置一下哈 ```yml spring: datasource: username: root password: root99 url: jdbc:mysql://localhost:3306/springboot_shiro_test?serverTimezone=Asia/Shanghai&useUnicode=true&characterEncoding=utf-8 driver-class-name: com.mysql.cj.jdbc.Driver mybatis: mapper-locations: classpath:mapper/*Mapper.xml type-aliases-package: cn.ideal.pojo server: port: 8080 ``` 具體的 Mapper 這裡還沒寫,講解的過程中,按照流需要,再寫上去 ## (2) 編寫 Mapper 因為程式碼是在文章之前寫好的,我們在後面會用到利用 username 進行查詢使用者和許可權的方法,所以,我們就按這樣寫就好了 ```java @Mapper public interface UserMapper { UserPojo queryUserByUsername(@Param("username") String username); Permission queryPermissionByUsername(@Param("username") String username); } ``` 具體的 XML 配置 sql 這部分涉及到多表的一個稍複雜的查詢,如果感覺有點吃力,可以去回顧一下前面的知識,或者乾脆不管也可以,接著看後面的,純瞭解 Shiro 也可以 ```xml ``` ## (3) 程式碼測試 ```java @SpringBootTest class Springboot13ShiroMybatisApplicationTests { @Autowired private UserMapper userMapper; @Test void contextLoads() { UserPojo admin = userMapper.queryUserByUsername("admin"); System.out.println(admin.toString()); Permission permission = userMapper.queryPermissionByUsername("admin"); System.out.println(permission.toString()); } } ``` # (五) Spring Boot 整合 Shiro ## (1) 自定義認證和授權(Realm) 首先我們需要建立Shiro的配置類,在config包下建立一個名為 ShiroConfig 的配置類 ```java @Configuration public class ShiroConfig { // 1、ShiroFilterFactoryBean // 2、DefaultWebSecurityManager // 3、Realm 物件(自定義) } ``` 上面註釋可以看出,我們需要在配置類中建立這樣幾個內容,由於他們幾個之間存在關聯,例如在 Manager 中關聯自己建立的 Realm,在最上面的過濾器,又關聯了中間這個 Manager,所以我們選擇倒著寫,先寫後面的(也就是被引用最早的 Realm),這樣就可以一層一層的在前面引用後面已經寫好的,會更舒服一些 首先,在 ShiroConfig 配置類中編寫一個方法用來獲取 Realm ,直接返回一個例項化的 userRealm() 就可以了 ```java /** * 建立 realm 物件,需要自己定義 * * @return */ @Bean public UserRealm userRealm() { return new UserRealm(); } ``` 具體內容,我們需要建立一個新的類來定義 我們自定義了一個 UserRealm類,同時繼承 AuthorizingRealm 類,接著就需要實現兩個方法: - doGetAuthenticationInfo() 認證方法:檢視使用者是否能通過認證,可簡單理解為登入是否成功 - doGetAuthorizationInfo() 授權方法:給當前已經登入成功的使用者劃分許可權以及分配角色 根據上面的介紹也很好理解,肯定是認證先行,接著才會執行授權方法,所以我們先來編寫認證的程式碼 ### A:認證 認證首先就要先獲取到我們前臺傳來的資料,這塊很顯然,交給 Controller 來做,我們先來完成這個內容,再回來編寫認證 說明:獲取前臺的資料就是下面的 login 方法,同時在其中呼叫了認證的方法,其他幾個方法,只是為了後期演示的時候使用,一塊給出來了,同時下面登入方法中我捕獲了所有異常,大家可以自己更細緻的劃分,同時由於為了演示重點,我前臺沒有做太多的處理,例如session中傳入一些登入失敗等的字串,完全不寫也是可以的哈 ```java @Controller public class UserController { @RequestMapping("/user/queryAll") @ResponseBody public String queryAll() { return "這是 user/queryAll 方法"; } @RequestMapping("/user/admin/add") @ResponseBody public String adminAdd() { return "這是 user/adminAdd 方法"; } @RequestMapping("/login") public String login(String username, String password, HttpServletRequest request) { // 由於是根據name引數獲取的,我這裡封裝了一下 UserPojo user = new UserPojo(); user.setUsername(username); user.setPassword(password); // 創建出一個 Token 內容本質基於前臺的使用者名稱和密碼(不一定正確) UsernamePasswordToken token = new UsernamePasswordToken(username, password); // 獲取 subject 認證主體(這裡也就是現在登入的使用者) Subject subject = SecurityUtils.getSubject(); try{ // 認證開始,這裡會跳轉到自定義的 UserRealm 中 subject.login(token); // 可以儲存到 session 中 request.getSession().setAttribute("user", user); return "views/success"; }catch(Exception e){ // 捕獲異常 e.printStackTrace(); request.getSession().setAttribute("user", user); request.setAttribute("errorMsg", "兄弟,使用者名稱或密碼錯誤"); return "views/login"; } } } ``` UserRealm 下的認證方法: 說明:通過方法引數中的 token 就可以獲取到我們剛才的那個 token資訊,最方便的方法就是下面,直接通過 getPrincipal() 獲取到使用者名稱(Object 轉 String),還有一種方法就是,將 Token 強轉了 UsernamePasswordToken 型別,接著需要使用者名稱或者密碼等資訊都可以通過 getxxx 的方法獲取到 可以看到,我們只需要將資料庫中查詢到的資料交給 Shiro 去做認證就可以了,具體細節都被封裝了 補充:userService.queryUserByUsername(username) 方法只是呼叫返回了 UserMapper 中根據使用者名稱查詢使用者資訊的方法,只是為了結構完整,沒涉及任何業務,如果不清楚,可以去 GitHub 看一下原始碼 ```java /** * 認證 * * @param authenticationToken * @return * @throws AuthenticationException */ @Override protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException { // 根據在接受前臺資料建立的 Token 獲取使用者名稱 String username = (String) authenticationToken.getPrincipal(); // UsernamePasswordToken userToken = (UsernamePasswordToken) authenticationToken; // System.out.println(userToken.getPrincipal()); // System.out.println(userToken.getUsername()); // System.out.println(userToken.getPassword()); // 通過使用者名稱查詢相關的使用者資訊(實體) UserPojo user = userService.queryUserByUsername(username); if (user != null) { // 存入 Session,可選 SecurityUtils.getSubject().getSession().setAttribute("user", user); // 密碼認證的工作,Shiro 來做 AuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(user.getUsername(), user.getPassword(), "userRealm"); return authenticationInfo; } else { // 返回 null 即會拋異常 return null; } } ``` ### B:授權 授權,也就是在使用者認證後,來設定使用者的許可權或者角色資訊,這裡主要是獲取到使用者名稱以後,通過 service 中呼叫 mapper 接著根據使用者名稱查詢使用者或者許可權,由於返回的是使用者或者許可權實體物件,所以配合 getxxx等方法就可以獲取到需要的值了 當然了,最主要的還是根據自己 mapper 以及表的返回情況設定,這裡只要能獲取到角色以及許可權資訊(這裡是 String 型別)就可以了,如果是多個角色,就要使用 setRoles() 方法了,具體需要可以看引數和返回值,或者查閱文件,這裡演示都是單個的 ```java /** * 授權 * * @param principalCollection * @return */ @Override protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) { // 獲取使用者名稱資訊 String username = (String) principalCollection.getPrimaryPrincipal(); // 建立一個簡單授權驗證資訊 SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo(); // 給這個使用者設定從 role 表獲取到的角色資訊 authorizationInfo.addRole(userService.queryUserByUsername(username).getRole().getRoleName()); //給這個使用者設定從 permission 表獲取的許可權資訊 authorizationInfo.addStringPermission(userService.queryPermissionByUsername(username).getPermissionName()); return authorizationInfo; } ``` ## (2) Shiro 配置 授權和配置就寫好了,也就是說 Realm 完事了,一個大頭內容完成了,我們接著就可以回到 Shiro 的配置中去了,繼續倒著寫,開始寫關於第二點 Manager 的內容 ```java @Configuration public class ShiroConfig { // 1、ShiroFilterFactoryBean // 2、DefaultWebSecurityManager // 3、Realm 物件(自定義) @Bean public UserRealm userRealm() { return new UserRealm(); } } ``` ### A:配置安全管理器 接著就來配置安全管理器(SecurityManager),這裡就需要將剛才寫好的 Realm 引入進來,這樣 Shiro 就可以訪問 Realm 了,然後接著返回 ```java /** * 配置安全管理器 SecurityManager * * @return */ @Bean public DefaultWebSecurityManager securityManager() { // 將自定義 Realm 加進來 DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); // 關聯 Realm securityManager.setRealm(userRealm()); return securityManager; } ``` 如果,setRealm 的時候直接呼叫下面的 userRealm() 出現了問題,那麼可以考慮在方法引數中配合 @Qualifier 使用,它會自動去找下面 public UserRealm userRealm() 方法的方法名 userRealm,userRealm 中的註解不指定name也行,這裡只是為了讓大家看得更明白 ```java @Bean public DefaultWebSecurityManager securityManager(@Qualifier("userRealm") UserRealm userRealm) { // 將自定義 Realm 加進來 DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); // 關聯 Realm securityManager.setRealm(userRealm); return securityManager; } @Bean(name="userRealm") public UserRealm userRealm() { return new UserRealm(); } ``` ### B:配置過濾器 這又是一個關鍵的地方,首先建立一個 ShiroFilterFactoryBean 肯定是毋庸置疑的,最後畢竟要返回這個物件,首先就是將剛才的 securityManager 關聯進來了,也就是說層層呼叫,最終把 Realm 關聯過來了,接著要寫的就是重頭戲了,我們接著需要設定一些自己定義的內容 - 自定義登入頁面 - 成功頁面 - 未授權介面 - 一個自定義的 Map 用來儲存需要放行或者攔截的請求 - 登出頁面 重點說一下攔截放行(Map)這塊:通過 map 鍵值對的形式儲存,key 儲存 URL ,value 儲存對應的一些許可權或者角色等等,其實 key 這塊還是很好理解的,例如 :`/css/** `、`/user/admin/**` 分別代表 css 資料夾下的所有檔案,以及請求路徑字首為 `/user/admin/ ` URL,而對應的 value 就有一定的規範了 關鍵: - anon:無需認證,即可訪問,也就是遊客也可以訪問 - authc:必須認證,才能訪問,也就是例如需要登入後 - roles[xxx] :比如擁有某種角色身份才能訪問 ,注:xxx為角色引數 - perms[xxx]:必須擁有對某個請求、資源的相關許可權才能訪問,注:xxx為許可權引數 補充: - user:必須使用【記住我】這個功能才能訪問 - logout:登出,執行後跳轉到設定好的登入頁面去 ```java /** * 配置 Shiro 過濾器 * * @param securityManager * @return */ @Bean public ShiroFilterFactoryBean shiroFilter(DefaultWebSecurityManager securityManager) { // 定義 shiroFactoryBean ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean(); // 關聯 securityManager shiroFilterFactoryBean.setSecurityManager(securityManager); // 自定義登入頁面,如果登入的時候,就會執行這個請求,即跳轉到登入頁 shiroFilterFactoryBean.setLoginUrl("/toLoginPage"); // 指定成功頁面 shiroFilterFactoryBean.setSuccessUrl("/success"); // 指定未授權介面 shiroFilterFactoryBean.setUnauthorizedUrl("/unauthorized"); // LinkedHashMap 是有序的,進行順序攔截器配置