Shiro框架:授权流程、授权方式、Shiro授权入门程序、自定义Realm进行授权
一、Shiro授權(quán):
1、授權(quán)與權(quán)限:
(1)授權(quán):訪問控制,必須具有該資源的訪問權(quán)限才可以訪問該資源。
(2)權(quán)限模型:標(biāo)準(zhǔn)權(quán)限數(shù)據(jù)模型包括 :用戶、角色、權(quán)限(包括資源和權(quán)限)、用戶角色關(guān)系、角色權(quán)限關(guān)系。
(3)權(quán)限分配:通過UI界面方便給用戶分配權(quán)限,對上邊權(quán)限模型進(jìn)行增、刪、改、查操作。
(4)權(quán)限控制:
第一種:基于角色的權(quán)限控制:根據(jù)角色判斷是否有操作權(quán)限,因?yàn)榻巧淖兓暂^高,如果角色修改需要修改控制代碼,系統(tǒng)可擴(kuò)展性不強(qiáng)。
第二種:基于資源的權(quán)限控制:根據(jù)資源權(quán)限判斷是否有操作權(quán)限,因?yàn)橘Y源較為固定,如果角色修改或角色中權(quán)限修改不需要修改控制代碼,使用此方法系統(tǒng)可維護(hù)性很強(qiáng)。建議使用。
(5)權(quán)限管理的解決方案:
①對于粗顆粒權(quán)限管理,建議在系統(tǒng)架構(gòu)層面去解決,寫系統(tǒng)架構(gòu)級(jí)別統(tǒng)一代碼(基礎(chǔ)代碼)。
粗顆粒權(quán)限:比如對系統(tǒng)的url、菜單、jsp頁面、頁面上按鈕、類方法進(jìn)行權(quán)限管理,即對資源類型進(jìn)行權(quán)限管理。
②對于細(xì)顆粒權(quán)限管理:細(xì)顆粒權(quán)限管理是系統(tǒng)的業(yè)務(wù)邏輯,業(yè)務(wù)邏輯代碼不方便抽取統(tǒng)一代碼,建議在系統(tǒng)業(yè)務(wù)層進(jìn)行處理。
粗顆粒權(quán)限:比如用戶id為001的用戶信息(資源實(shí)例)、類型為t01的商品信息(資源實(shí)例),對資源實(shí)例進(jìn)行權(quán)限管理,可以理解為對數(shù)據(jù)級(jí)別的權(quán)限管理。
?
2、授權(quán)流程:
(1)對subject進(jìn)行授權(quán),調(diào)用方法isPermitted("permission串");
(2)SecurityManager執(zhí)行授權(quán),通過ModularRealmAuthorizer執(zhí)行授權(quán);
(3)ModularRealmAuthorizer執(zhí)行realm(自定義的CustomRealm)從數(shù)據(jù)庫查詢權(quán)限數(shù)據(jù),調(diào)用realm的授權(quán)方法:doGetAuthorizationInfo;
(4)realm從數(shù)據(jù)庫查詢權(quán)限數(shù)據(jù),返回ModularRealmAuthorizer;
(5)ModularRealmAuthorizer調(diào)用PermissionResolver進(jìn)行權(quán)限串比對;
(6)如果比對后,isPermitted中"permission串"在realm查詢到權(quán)限數(shù)據(jù)中,說明用戶訪問permission串有權(quán)限,否則 沒有權(quán)限,拋出異常。
?
3、Shiro 支持三種方式的授權(quán):
(1)編程式:通過寫if/else 授權(quán)代碼塊完成:
Subject subject = SecurityUtils.getSubject();
if(subject.hasRole(“admin”)) {
//有權(quán)限
} else {
//無權(quán)限
}
(2)注解式:通過在執(zhí)行的Java方法上放置相應(yīng)的注解完成:
@RequiresRoles("admin")
public void hello() {
//有權(quán)限
}
(3)JSP/GSP 標(biāo)簽:在JSP/GSP 頁面通過相應(yīng)的標(biāo)簽完成:
<shiro:hasRole name="admin">
<!— 有權(quán)限—>
</shiro:hasRole>
?
?
二、Shiro授權(quán)示例程序:
1、入門的Shiro授權(quán)程序:
(1)編寫shiro-permission.ini文件:
shiro-permission.ini文件里邊的內(nèi)容相當(dāng)于在數(shù)據(jù)庫查詢出來的;
#用戶 [users] #用戶zhangsan的密碼是123,此用戶具有role1和role2兩個(gè)角色 zhangsan=123456,role1,role2 wangwu=123456,role2#權(quán)限 [roles] #角色role1對資源user擁有create、update權(quán)限 role1=user:create,user:update role2=user:create,items:delete role3=user:create權(quán)限標(biāo)識(shí)符號(hào)規(guī)則:資源:操作:實(shí)例(中間使用半角:分隔)
user:create:01? 表示對用戶資源的01實(shí)例進(jìn)行create操作。
user:create? ? 表示對用戶資源進(jìn)行create操作,相當(dāng)于user:create:*,對所有用戶資源實(shí)例進(jìn)行create操作。
user:*:01? 表示對用戶資源實(shí)例01進(jìn)行所有操作。
(2)程序編寫:
//shiro的授權(quán)測試: public class AuthorizationTest {//角色授權(quán)、資源授權(quán)測試:@Testpublic void testAuthorization(){Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro-permission.ini");SecurityManager securityManager = factory.getInstance();SecurityUtils.setSecurityManager(securityManager);SecurityUtils.setSecurityManager(securityManager);Subject subject = SecurityUtils.getSubject();UsernamePasswordToken token = new UsernamePasswordToken("zhangsan","123456");try {subject.login(token);} catch (AuthenticationException e) {e.printStackTrace();}System.out.println("認(rèn)證狀態(tài):" + subject.isAuthenticated());//認(rèn)證通過之后執(zhí)行授權(quán)://基于角色的授權(quán)//hasRole傳入角色標(biāo)識(shí):boolean ishasRole = subject.hasRole("role1");System.out.println("單個(gè)角色判斷" + ishasRole);//hasAllRoles是否擁有多個(gè)角色:boolean hasAllRoles = subject.hasAllRoles(Arrays.asList("role1","role2","role3"));System.out.println("多個(gè)角色判斷" + hasAllRoles);// 使用check方法進(jìn)行授權(quán),如果授權(quán)不通過會(huì)拋出異常subject.checkRole("role2");//基于資源的授權(quán)://isPermitted傳入權(quán)限標(biāo)識(shí)符boolean isPermitted = subject.isPermitted("user:create:1");System.out.println("單個(gè)權(quán)限判斷" + isPermitted);boolean isPermittedAll = subject.isPermittedAll("user:create:1","user:delete");System.out.println("多個(gè)權(quán)限判斷" + isPermittedAll);// 使用check方法進(jìn)行授權(quán),如果授權(quán)不通過會(huì)拋出異常subject.checkPermission("items:delete:1");} }(3)執(zhí)行結(jié)果:
至此,Shiro授權(quán)入門程序就完成了。在這個(gè)程序中,我們讀取的是在shiro.ini配置文件中靜態(tài)配置好的權(quán)限內(nèi)容,但是在實(shí)際開發(fā),我們通常是從數(shù)據(jù)庫中查詢用戶所擁有的權(quán)限信息,因此,我們需要使用自定義的Realm進(jìn)行從數(shù)據(jù)庫中查詢用戶的權(quán)限信息。
?
2、自定義realm進(jìn)行授權(quán):
上面的程序是通過shiro-permission.ini對權(quán)限文件進(jìn)行靜態(tài)配置,在實(shí)際開發(fā)中,都是從數(shù)據(jù)庫中獲取權(quán)限數(shù)據(jù)。就需要自定義realm,由realm從數(shù)據(jù)庫查詢權(quán)限數(shù)據(jù)。
realm根據(jù)用戶身份查詢權(quán)限數(shù)據(jù),將權(quán)限數(shù)據(jù)返回給authorizer(授權(quán)器)。
(1)自定義realm:
//自定義的Realm,需要繼承AuthorizingRealm,并且重寫這個(gè)類的兩個(gè)方法 public class CustomRealm extends AuthorizingRealm{// 設(shè)置realm的名稱@Overridepublic void setName(String name) {super.setName("customRealm");}// 用于授權(quán)@Overrideprotected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {//從principals獲取身份信息//將getPrimaryPrincipal方法返回值轉(zhuǎn)為真實(shí)身份(在上邊的doGetAuthenticationInfo認(rèn)證通過填充到SimpleAuthenticationInfo中的身份類型)String userCode = (String) principals.getPrimaryPrincipal();//根據(jù)身份信息獲取權(quán)限信息//連接數(shù)據(jù)庫//模擬從數(shù)據(jù)庫獲取到數(shù)據(jù)List<String> permissions = new ArrayList<String>();permissions.add("user:create");//用戶的創(chuàng)建permissions.add("items:add");//商品添加權(quán)限//查到權(quán)限數(shù)據(jù),返回授權(quán)信息(要包括上邊的permissions)SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();//將上邊查詢到授權(quán)信息填充到simpleAuthorizationInfo對象中simpleAuthorizationInfo.addStringPermissions(permissions);return simpleAuthorizationInfo;} }(2)編寫shiro-realm.ini文件:
在shiro-realm.ini文件中配置自定義的realm,將realm設(shè)置到securityManager中。
[main] #自定義的realm customRealm=com.zwp.shiro.realm.CustomRealm #將realm設(shè)置到securityManager,相當(dāng)于spring中的注入 securityManager.realms=$customRealm(3)測試:
// 自定義realm進(jìn)行資源授權(quán)測試@Testpublic void testAuthorizationCustomRealm() {Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro-realm.ini");SecurityManager securityManager = factory.getInstance();SecurityUtils.setSecurityManager(securityManager);Subject subject = SecurityUtils.getSubject();// 創(chuàng)建token令牌UsernamePasswordToken token = new UsernamePasswordToken("zhangsan","123456");// 執(zhí)行認(rèn)證try {subject.login(token);} catch (AuthenticationException e) {e.printStackTrace();}System.out.println("認(rèn)證狀態(tài):" + subject.isAuthenticated());// 認(rèn)證通過后執(zhí)行授權(quán)// 基于資源的授權(quán),調(diào)用isPermitted方法會(huì)調(diào)用CustomRealm從數(shù)據(jù)庫查詢正確權(quán)限數(shù)據(jù)// isPermitted傳入權(quán)限標(biāo)識(shí)符,判斷user:create:1是否在CustomRealm查詢到權(quán)限數(shù)據(jù)之內(nèi)boolean isPermitted = subject.isPermitted("user:create:1");System.out.println("單個(gè)權(quán)限判斷" + isPermitted);boolean isPermittedAll = subject.isPermittedAll("user:create:1","user:create");System.out.println("多個(gè)權(quán)限判斷" + isPermittedAll);// 使用check方法進(jìn)行授權(quán),如果授權(quán)不通過會(huì)拋出異常subject.checkPermission("items:add:1");}(4)測試結(jié)果:
至此,Shiro使用自定義Realm進(jìn)行授權(quán)的程序就完成了。
?
與50位技術(shù)專家面對面20年技術(shù)見證,附贈(zèng)技術(shù)全景圖總結(jié)
以上是生活随笔為你收集整理的Shiro框架:授权流程、授权方式、Shiro授权入门程序、自定义Realm进行授权的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Shiro框架:Shiro简介、登陆认证
- 下一篇: SSM整合Shiro进行登陆认证和授权详