Spring Boot整合Shiro (使用shiro-spring-boot-web-starter)


Spring Boot 整合 Shiro 安全框架

同時整合 Druid 數據源、MyBatis 框架

整合 Druid 數據源是可選的

整合 MyBatis 框架只是為了登錄頁面展示數據庫的數據

三個框架並沒有依賴關系,按照任何順序整合都可以,也可以只整合Shiro

此章主要是關於 Shiro 的整合摸索,所以我將首先整合 Shiro

完整代碼和更多的文檔請移步Github springboot-05-shiro

建議對照觀看


Shiro 的基本功能和概念

此部分對應 shiro-quickstart 模塊

這是一個單獨的 Maven 項目,本質上就是 Shiro 官網的10分鍾快速上手

主要參考代碼是Github 樣例

也參考Shiro用starter方式優雅整合到SpringBoot中

因為 Shiro 屬於開源項目,所以文檔的維護並不是很及時與准確

一定要以最新版的源碼為准

必須了解的關於安全的概念

這兩個概念不理解,后面Shiro的授權一定會雲里霧里

  • Authentication:認證、鑒權
  • Authorization:授權

與Spring Boot整合

值得一提的是,目前網上的很多整合教程都是導入shiro-spring

我們知道,這個shiro-spring包本質上只是和Spring整合的包,導入之后我們還需要寫一個@Configuration用以和Spring Boot整合

事實上,已經有shiro-spring-boot-web-starter包發布,就像mybatis-spring-boot-starter一樣,它已經幫助我們完成了部分配置

導入之后我們還需要進行少量的配置就可以了

需要我們配置的部分

由於安全策略與具體的業務會有聯系,就比如說不同的項目所含有的角色和權限定義是完全不同的,所以這部分必定是我們自己配置

並不存在完全自動配置的情況

參考 官網對Shiro和Spring Boot應用整合的說明

目前存在兩者需要我們配置的部分

Realm

這個詞的中文翻譯是領域,Shiro在 前面的文檔 部分也對其做了解釋

我個人的理解是由於不同業務被認證和授權的主體不同,這里就是要定義這個主體是什么,以及如何對它進行授權和認證

Shiro 為我們提供了現成的Realm可以直接使用,本樣例中我使用類全限定名是org.apache.shiro.realm.jdbc.JdbcRealm

也就是從數據庫讀取用戶的信息 (用戶名、密碼、角色、權限),然后進行認證

JdbcRealm中定義了默認的查詢語句,我們根據查詢語句建立對應的數據庫表

protected static final String DEFAULT_AUTHENTICATION_QUERY="select password from users where username = ?";

protected static final String DEFAULT_SALTED_AUTHENTICATION_QUERY="select password, password_salt from users where username = ?";

protected static final String DEFAULT_USER_ROLES_QUERY="select role_name from user_roles where username = ?";

protected static final String DEFAULT_PERMISSIONS_QUERY="select permission from roles_permissions where role_name = ?";

當然,JdbcRealm是支持覆寫SQL語句的,你可以用set***Query方法覆寫內置的SQL語句

不過這里對SQL語句查詢結果應該還會有其他要求,具體的我還沒有研究,我使用的就是默認的

同時還需要設置一個數據源

private DataSource dataSource;

@Autowired
public void setDataSource(DataSource dataSource){
    this.dataSource=dataSource;
}

@Bean
public Realm realm(){
    JdbcRealm realm=new JdbcRealm();
    realm.setDataSource(dataSource);
    // 基於權限的資源訪問默認是關閉的
    realm.setPermissionsLookupEnabled(true);
    return realm;
}

那么由於我使用的是自帶提供的JdbcRealm,所以認證、授權的過程都不用我來具體實現,其還支持加鹽功能

ShiroFilterChainDefinition

定義完進行認證和授權的 Subject,下一步就是定義應該按照什么樣的規則進行認證和授權

官網關於認證的文檔

官網關於授權的文檔

Shiro框架支持通過URL或者注解配置認證和授權,這兩種方式沒有好壞之分,參考網上的說法,往往兩種結合才更有效

關於過濾器可以參考默認過濾器

這里貼出我寫的過濾規則

@Bean
public ShiroFilterChainDefinition shiroFilterChainDefinition(){
    DefaultShiroFilterChainDefinition chainDefinition=new DefaultShiroFilterChainDefinition();
    // 登出功能
    chainDefinition.addPathDefinition("/logout","logout");
    // 錯誤頁面無需認證
    chainDefinition.addPathDefinition("/error","anon");
    // druid連接池的角色控制,只有擁有admin角色的admin用戶可以訪問,不理解可以先不管
    chainDefinition.addPathDefinition("/druid/**","authc, roles[admin]");
    // 靜態資源無需認證
    chainDefinition.addPathDefinition("/static/**","anon");
    // 其余資源都需要認證
    chainDefinition.addPathDefinition("/**","authc");
    return chainDefinition;
}

大體思想是在URL中配置認證規則 (鑒權),在Controller中使用注解配置授權,這樣的優勢:

  1. 減少代碼量,不必為每個Controller都寫上鑒權規則
  2. 利用注解可以細粒度設置基於角色或者基於資源的權限

基於角色的訪問控制

現在我們來看這一條規則

chainDefinition.addPathDefinition("/druid/**","authc, roles[admin]");

由於在配置完Shiro后,我為項目整合了 Druid
數據源,如果你對它不是很了解,建議去查看Github 文檔

這里無需對 Druid 有很詳細的了解,我想闡述的最關鍵的一點是,當你整合成功 Druid 框架,並且開啟了 Web 統計功能 (參考我的application.yml)

訪問你的 項目URL/druid 會進入 Druid 數據源的管理界面,這里需要輸入你之前設置的用戶名和密碼才能查看項目對每一條執行過的SQL的統計情況

顯然這個功能我不希望普通角色的用戶也能查看,所以我將其設置為所有匹配規則 /druid/** 的URL都需要登錄並且需要有admin角色

對應的,你可以嘗試使用admin用戶去登錄並訪問/druid頁面,我已經將admin用戶設置為admin角色 (這里可能有一些繞,原諒我是為了省事才把兩個名字設置相同的,這里的用戶名完全可以修改為你自己的名字!)

之后,再嘗試使用andy67123用戶去登錄並訪問/druid頁面,它的角色僅僅是訪客,看看會有什么不同

類似的,還有一處使用注解來控制角色訪問

AccountInfoController中,有這么一段代碼表明這處的資源需要admin角色才能訪問

@RequiresRoles("admin")
@RequestMapping("/account-info")
public String accountInfoTemplate(Model model){
    ...
}

基於權限的訪問控制

最后,我們來聊Shiro中常用功能同樣也很重要的一部分——Permissions

先上官方文檔 Understanding Permissions in Apache Shiro

這部分我也是想了很久,什么時候需要使用基於角色的訪問控制,什么時候需要使用基於資源的訪問控制,什么時候可以兩者合並使用

誠然,你的系統完全可以只使用基於角色的訪問控制,在此樣例中就只需要usersuser_roles兩張表,然后在Controller使用@RequiresRoles("role")注解去指定角色

也可以只使用基於權限的訪問控制 (依然需要角色,但是不再通過角色控制訪問),在此樣例中需要usersuser_rolesroles_permissions
三張表,然后在Controller使用@RequiresPermissions("perm")注解去指定權限

這一部分關於如何設計以及誰優誰劣先暫且不討論,因為我也不知道

此處先把 Shiro 的 Permissions 樣例展示一下

首先查看角色和權限對應的關系

# 角色 權限
1 admin manage:*
2 訪客 read:*
3 java開發 read:*
4 java開發 dev:java
5 python開發 read:*
6 python開發 dev:python

也可以參考進入的/login頁面提供的信息

  • admin角色擁有所有的管理權限
  • 訪客只有查看文檔的權限
  • java開發可以查看文檔和進行java代碼開發
  • python開發可以查看文檔和進行python代碼開發

再查看用戶和角色對應的關系

# 用戶 角色
1 admin admin
2 andy67123 訪客
3 admin java開發
4 admin python開發
5 java java開發
6 python python開發
  • admin用戶擁有adminjava開發python開發三種角色
  • andy67123用戶擁有訪客角色
  • java用戶擁有java開發角色
  • python用戶擁有python開發角色

請試一試登錄完成后,在主頁點擊各個按鈕的結果,是否實現了各資源的權限控制


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM