權限管理及shiro框架

權限管理及shiro框架

權限管理簡介

    做系統時肯定遇到最常見的就是不同的用戶需求是不一樣的,就拿登陸來說,一個辦公管理系統,不同部門的人肯定要求的功能和權限是不一樣的,那你不可能對每一個部門都寫一個登陸頁面,給不同的url吧!亦或者在下邊選擇你是什麼部門的人?那每個部門還有等級。再繼續選,然後個每個人寫一個界面?那明顯是不可能的,那我們到底要怎麼實現?

    最常用的方法就是劃分不同的角色,賦予角色權限,然後再讓用戶去申請角色就好了,具體的實現慢慢說。

RBAC

RBAC基於角色的權限管理。簡單理解爲誰扮演什麼角色,被允許做什麼操作。

  • 用戶對象user:當前操作用戶
  • 角色對象role:表示權限操作許可權的集合
  • 權限對象permission:資源操作許可權

例子:張三(user)下載(permission)一個高清無碼的種子(資源),需要VIP權限(role)

張三--->普通用戶--->授權---->VIP用戶----->下載種子

根據角色授權的思想,我們需要涉及五張表)

三張主表

  1. 用戶表
  2. 角色表
  3. 權限表

兩張中間表

  1. 用戶角色表(user_role)
  2. 角色資源表(permission)

    上圖稱爲權限管理的通用模型,不過企業在開發中根據系統自身的特點還會對上圖進行修改,但是用戶、角色、權限、用戶角色關係、角色權限關係需要去理解。

shiro權限管理

shiro基本概念

shiro權限管理框架提供了用戶身份認證授權兩部分,簡稱認證授權。

用戶身份認證流程

身份認證就是判斷一個用戶是否爲合法用戶的處理過程.醉常用的簡單身份認證方式是系統通過覈對用戶輸入的用戶名和口令,看其是否與系統中存儲的該用戶的用戶名和口令一致,來判斷用戶身份是否正確.對於採用指紋等系統,則出示指紋;對於硬件Key等刷卡系統,則需要刷卡。

用戶授權流程

授權,即訪問控制,控制誰能訪問哪些資源。主體進行身份認證後需要分配權限方可訪問系統的資源,對於某些資源沒有權限是無法訪問的。

    Apcache Shiro是Java的一個安全框架。幫助我們完成:認證、授權、加密、會話管理、與Web集成、緩存等。

    從功能角度看:shiro

Authentication:身份認證/登錄,驗證用戶是不是擁有相應的身份;

Authorization:授權,即權限驗證,驗證某個已認證的用戶是否擁有某個權限;即判斷用戶是否能做事情,常見的如:驗證某個用戶是否擁有某個角色。或者細粒度的驗證某個用戶對某個資源是否具有某個權限;

Session Manager:會話管理,即用戶登錄後就是一次會話,在沒有退出之前,它的所有信息都在會話中;會話可以是普通JavaSE環境的,也可以是Web環境的;

Cryptography:加密,保護數據的安全性,如密碼加密存儲到數據庫,而不是明文存儲;

Web Support:Web支持,可以非常容易的集成到Web環境;

Caching:緩存,比如用戶登錄後,其用戶信息、擁有的角色/權限不必每次去查,這樣可以提高效率;

Concurrency:shiro支持多線程應用的併發驗證,即如在一個線程中開啓另一個線程,能把權限自動傳播過去;

Testing:提供測試支持;

Run As:允許一個用戶假裝爲另一個用戶(如果他們允許)的身份進行訪問;

Remember Me:記住我,這個是非常常見的功能,即一次登錄後,下次再來的話不用登錄了。

    Shiro架構有三個主要概念—Subject,SecurityManager、Realms

Subject

訪問系統的用戶,主體可以是用戶、程序等,進行認證的都稱爲主體;Subject一詞是一個安全術語,其基本意思是"當前的操作用戶"。它是一個抽象的概念,可以是人,也可以是第三方進程或其他類似事物,如爬蟲,機器人等。在程序任意位置:Subject currentUser = SecurityUtils.getSubject(); 獲取shiro一旦獲得Subject,你就可以立即獲得你希望用Shiro爲當前用戶做的90%的事情,如登錄、登出、訪問會話、執行授權檢查等

SecurityManager

安全管理器,它是shiro功能實現的核心,負責與後邊介紹的其他組件(認證器/授權器/緩存控制器)進行交互,實現subject委託的各種功能。有點類似於spirngmvc中的DispatcherServlet前端控制器。

Realms

Realm充當了Shiro與應用安全數據間的"橋樑"或者"連接器"。;可以把Realm看成DataSource,即安全數據源。執行認證(登錄)和授權(訪問控制)時,Shiro會從應用配置的Realm中查找相關的比對數據。以確認用戶是否合法,操作是否合理

    從系統結構角度看:shiro

Subject:主體,可以看到主體可以是任何可以與應用交互的"用戶";

SecurityManager:相當於SpringMVC中的DispatcherServlet或者Struts2中的FilterDispatcher;是Shiro的心臟;所有具體的交互都通過SecurityManager進行控制;它管理着所有Subject、且負責進行認證和授權、及會話、緩存的管理。

Authenticator:認證器,負責主體認證的,這是一個擴展點,如果用戶覺得Shiro默認的不好,可以自定義實現;其需要認證策略(Authentication Strategy),即什麼情況下算用戶認證通過了;

Authorizer:授權器,或者訪問控制器,用來決定主體是否有權限進行相應的操作;即控制着用戶能訪問應用中的哪些功能;

Realm:可以有1個或多個Realm,可以認爲是安全實體數據源,即用於獲取安全實體的;可以是JDBC實現,也可以是LDAP實現,或者內存實現等等;由用戶提供;注意:Shiro不知道你的用戶/權限存儲在哪及以何種格式存儲;所以我們一般在應用中都需要實現自己的Realm;

SessionManager:如果寫過Servlet就應該知道Session的概念,Session呢需要有人去管理它的生命週期,這個組件就是SessionManager;而Shiro並不僅僅可以用在Web環境,也可以用在如普通的JavaSE環境、EJB等環境;所有呢,Shiro就抽象了一個自己的Session來管理主體與應用之間交互的數據;可以實現分佈式的會話管理;

SessionDAO:DAO大家都用過,數據訪問對象,用於會話的CRUD,比如我們想把Session保存到數據庫,那麼可以實現自己的SessionDAO,通過如JDBC寫到數據庫;比如想把Session放到redis中,可以實現自己的redis SessionDAO;另外SessionDAO中可以使用Cache進行緩存,以提高性能;

CacheManager:緩存控制器,來管理如用戶、角色、權限等的緩存的;因爲這些數據基本上很少去改變,放到緩存中後可以提高訪問的性能

Cryptography:密碼模塊,Shiro提高了一些常見的加密組件用於如密碼加密/解密的。

shiro認證

使用ini完成認證

認證步驟:

1:拷貝依賴

2:配置shiro.ini配置文件,模擬數據庫用戶列表

3.執行shiro登錄登出操作

認證操作常見的異常:

shiro登錄登出流程分析

1、調用subject.login方法進行登錄,其會自動委託給securityManager.login方法進行登錄;

2、securityManager通過Authenticator(認證器)進行認證;

3、Authenticator的實現ModularRealmAuthenticator調用realm從ini配置文件取用戶真實的賬號和密碼,這裏使用的是IniRealm(shiro自帶,相當於數據源);

4、IniRealm先根據token中的賬號去ini中找該賬號,如果找不到則給ModularRealmAuthenticator返回null,如果找到則匹配密碼,匹配密碼成功則認證通過。

5、最後調用Subject.logout進行退出操作。

自定義realm

步驟:

1:自定義reaml,繼承 AuthorizingRealm 重寫3方法:getName doGetAuthorizationInfo doGetAuthenticationInfo

2:配置ini文件,指定使用自定義realm

授權方式

權限表達式定義

在ini文件中用戶、角色、權限的配置規則是:"用戶名=密碼,角色1,角色2..." "角色=權限1,權限2...",首先根據用戶名找角色,再根據角色找權限,角色是權限集合。

權限字符串的規則是:"資源標識符:操作:資源實例標識符",意思是對哪個資源的哪個實例具有什麼操作,":"是資源/操作/實例的分割符,權限字符串也可以使用*通配符。

例子:

用戶創建權限:user:create,或user:create:*

用戶修改實例001的權限:user:update:001

用戶實例001的所有權限:user:*:001

一般而已,我們操作只需要關注前面兩節:

資源:操作 :

*:* : 所有資源的所有操作權限--->admin

使用ini方式判斷是否有角色/權限

步驟:

1:配置ini文件

2:加載配置文件,測試用戶是否擁有角色

自定義realm完成授權

步驟

1:自定義PermissionRealm繼承AuthorizingRealm重寫3個方法:getName doGetAuthorizationInfo doGetAuthenticationInfo

2

授權源碼分析

1、首先調用Subject.isPermitted*/hasRole*接口,其會委託給SecurityManager,而SecurityManager接着會委託給Authorizer

2、Authorizer是真正的授權者,如果我們調用如isPermitted("user:view"),其首先會通過PermissionResolver把字符串轉換成相應的Permission實例;

3、在進行授權之前,其會調用相應的Realm獲取Subject相應的角色/權限用於匹配傳入的角色/權限;

4、Authorizer會判斷Realm的角色/權限是否和傳入的匹配,如果有多個Realm,會委託給ModularRealmAuthorizer進行循環判斷,如果匹配如isPermitted*/hasRole*會返回true,否則返回false表示授權失敗。

Web集成

Shiro與Web集成,主要是通過配置一個ShiroFilter攔截所有URL,其中ShiroFilter類似於如Strut2/SpringMVC這種web框架的前端控制器,是所有請求入口點,負責根據配置(如ini配置文件),判斷請求進入URL是否需要登錄/權限等工作。

web項目集成shiro

步驟

1:導入相關依賴jar包,多出一個shiro-web.jar包

2:在web.xml文件中配置shiro的過濾器shiroFilter

3:配置shiro.ini配置文件

shiro默認過濾器

過濾器簡稱        對應的java類

anon        org.apache.shiro.web.filter.authc.AnonymousFilter

authc        org.apache.shiro.web.filter.authc.FormAuthenticationFilter

authcBasic        org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter

roles        org.apache.shiro.web.filter.authz.RolesAuthorizationFilter

perms        org.apache.shiro.web.filter.authz.PermissionsAuthorizationFilter

user        org.apache.shiro.web.filter.authc.UserFilter

logout        org.apache.shiro.web.filter.authc.LogoutFilter

port        org.apache.shiro.web.filter.authz.PortFilter

rest        org.apache.shiro.web.filter.authz.HttpMethodPermissionFilter

ssl        org.apache.shiro.web.filter.authz.SslFilter

anon:匿名攔截器,即不需要登錄即可訪問;一般用於靜態資源過濾;示例"/static/**=anon"

authc:表示需要認證(登錄)才能使用;示例"/**=authc"

主要屬性:usernameParam:表單提交的用戶名參數名( username); passwordParam:表單提交的密碼參數名(password); rememberMeParam:表單提交的密碼參數名(rememberMe);loginUrl:登錄頁面地址(/login.jsp);successUrl:登錄成功後的默認重定向地址; failureKeyAttribute:登錄失敗後錯誤信息存儲key(shiroLoginFailure);

authcBasic:Basic HTTP身份驗證攔截器,主要屬性: applicationName:彈出登錄框顯示的信息(application);

roles:角色授權攔截器,驗證用戶是否擁有資源角色;示例"/admin/**=roles[admin]"

perms:權限授權攔截器,驗證用戶是否擁有資源權限;示例"/user/create=perms["user:create"]"

user:用戶攔截器,用戶已經身份驗證/記住我登錄的都可;示例"/index=user"

logout:退出攔截器,主要屬性:redirectUrl:退出成功後重定向的地址(/);示例"/logout=logout"

port:端口攔截器,主要屬性:port(80):可以通過的端口;示例"/test= port[80]",如果用戶訪問該頁面是非80,將自動將請求端口改爲80並重定向到該80端口,其他路徑/參數等都一樣

rest:rest風格攔截器,自動根據請求方法構建權限字符串(GET=read, POST=create,PUT=update,DELETE=delete,HEAD=read,TRACE=read,OPTIONS=read, MKCOL=create)構建權限字符串;

示例"/users=rest[user]",會自動拼出"user:read,user:create,user:update,user:delete"權限字符串進行權限匹配(所有都得匹配,isPermittedAll);

ssl:SSL攔截器,只有請求協議是https才能通過;否則自動跳轉會https端口(443);其他和port攔截器一樣;

注:

anon,authcBasic,auchc,user是認證過濾器,

perms,roles,ssl,rest,port是授權過濾器

shiro登錄攔截器解析

authc登錄攔截器工作原理

authc攔截器有2個作用:

1>登錄認證

請求進來時,攔截並判斷當前用戶是否登錄了,如果已經登錄了放行, 如果沒有登錄,跳轉到authc.loginUrl屬性配置的路徑,注意:默認是/login.jsp

2>執行登錄認證

請求進來時,如果請求的路徑爲authc.loginUrl屬性配置的路徑(沒配置,默認是/login.jsp)時,如果當前用戶沒有登錄,authc這個攔截器會嘗試獲取請求中的賬號跟密碼值,然後比對ini配置文件或者realm中的用戶列表,如果比對正確,直接執行登錄操作,反之,拋異常,跳轉到authc.loginUrl指定的路徑。

注意:請求中賬號與密碼必須固定爲username 跟password, 如果需要改動必須額外指定,authc.usernameParam=xxx authc.passwordParam=xxxx

authc登錄成功之後處理邏輯:

authc登錄失敗之後處理邏輯:

Shiro的jsp標籤

步驟

1:在jsp中引入shiro標籤庫

2:標籤是否擁有權限進而顯示操作按鈕

 

spring集成-項目準備

步驟:

1:解壓:shiro-spring.zip 文件

2:將shiro-spring文件導入idea中

3:創建一個shiro數據庫, utf-8編碼

4:導入shiro.sql數據

5:修改resources/jdbc.properties中username跟password 值

6:配置tomcat服務器

7:啓動tomcat服務器訪問:http://localhost:8080/main

 

spring集成-shiro配置

步驟:

1:添加shiro與spring集成依賴jar包

2:在web.xml中配置shiro與spring框架集成需要shiroFilter代理類

3:配置shiro配置文件

    1>拷貝spring.xml文件, 刪除調用除了根元素之外的所有內容,然後配置shiro相關操作

2>在mvc.xml文件中配置引入spring-shiro.xml文件

4:測試,啓動服務器,訪問:http://localhost:8080/main

shiro登錄操作

步驟:

1:重寫LoginController類,實現登錄操作

2:重寫UserRealm中的doGetAuthenticationInfo, 注意需要注入IUserDAO對象操作數據庫

在spring-shiro.xml文件中,修改自定義UserRealm,注入IUserDAO屬性值

3:先請求/main, 再登錄,登錄成功直接跳轉到main請求路徑

shiro靜態授權

步驟:

1:分析權限控制選擇

1>編程式,缺點:必須進入請求方法中才能判斷是否有權限,放棄

2>jsp標籤方式, 缺點:雖然在頁面上沒有顯式請求按鈕,但是可以通過瀏覽器地址欄中輸入請求訪問, 放棄

3>註解方式:優點,可以在請求進入方法之前進行權限控制。 推薦

2:在需要權限控制的方法上面貼上權限標籤:(此處僅僅討論居於權限的表達式空:permission)

3:在spring-shiro.xml文件中配置權限註解支持, 讓權限註解生效@RequiresPermissions

4:添加用戶權限(靜態操作方式:模擬查詢數據庫)

5:在spring-shiro.xml配置沒有權限異常信息統一處理方式:原先在shiroFilter配置是無效的,因爲springmvc重新定製異常處理方式

6:測試, 分別使用zhangsan 與admin賬號登錄, 點擊不同請求觀察效果

shiro權限-角色-用戶關係分析

用戶-角色-權限數據初始化(權限的分配)

步驟:

1:在role表中添加2個角色 部門經理(deptMgr) 人事經理(empMgr)

2:給人事經理分配權限:員工的crud權限

在role_permission表中添加4條數據

如上圖操作, 此時人事經理這個角色被允許執行員工列表 員工刪除 員工保存 員工編輯的操作(權限)

3:給用戶指派某個角色:給zhangsan指定人事經理這個角色

在user_role表中添加1條數據

如上圖操作, 此時張三這個用戶扮演人事經理這個角色,被允許執行執行員工列表 員工刪除 員工保存 員工編輯的操作

數據庫方式授權

步驟:

1: 需要執行上述的數據權限分配

2:在自定義的UserRealm添加2個屬性:IRoleDAO IPermissionDAO

注意:同時修改spring-shiro.xml文件中UserRealm定義,注入dao實現類

3:重寫改動原先授權操作,改爲使用數據庫的方式授權

4:測試

1>先使用zhangsan賬號登錄查看是否有部門操作權限, 如果沒有表示授權成功

2>再使用admin賬號登錄,查看是否有部門操作權 如果沒有表示授權失敗

 

 

根據權限顯示列表