Shiro學習之許可權認證
許可權認證也就是訪問控制,即在應用中控制誰能訪問哪些資源.
在許可權認證中,最核心的是三個要素是:許可權,角色和使用者.
許可權,即操作資源的權力,比如訪問某個頁面,以及對某個模組的資料的新增,修改,刪除,檢視的權利(CRUD).
角色,是許可權的集合,一個角色可以包含多種許可權
使用者,在shiro中代表訪問系統的使用者,即subject
授權
- 程式設計式授權,基於角色和許可權的訪問控制
- 註解授權,jsp標籤授權
1.基於角色的訪問控制
配置shiro_role.ini檔案
[users]
yyt=123,role1,role2
jack=1234,role1
規則即:“使用者名稱=密碼,角色1,角色2”,如果需要在應用中判斷使用者是否有相應角色,就需要在相應的Realm中返回角色資訊,也就是說Shiro不負責維護使用者-角色資訊,需要應用提供,Shiro只是提供相應的介面方便驗證,後續會介紹如何動態的獲取使用者角色。
首先我將重複的程式碼封裝成一個方法,傳入配置檔案的名字,使用者名稱,密碼
package com.kingsky;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.config.IniSecurityManagerFactory;
import org.apache.shiro.mgt.SecurityManager ;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.util.Factory;
public class ShiroUtil {
public static Subject login(String configPath, String userName,
String passWord) {
// 讀取配置檔案,初始化SecurityManager工廠
Factory<SecurityManager> factory = new IniSecurityManagerFactory(
"classpath:" +configPath);
// 獲取到SecurityManager例項
SecurityManager securityManager = factory.getInstance();
// 把SecurityManager繫結到SecurityUtils中
SecurityUtils.setSecurityManager(securityManager);
// 得到當前使用者
Subject subject = SecurityUtils.getSubject();
// 建立Token令牌,使用者名稱/密碼
UsernamePasswordToken passwordToken = new UsernamePasswordToken(userName,
passWord);
// 驗證登入 會丟擲異常
try {
subject.login(passwordToken);
System.out.println("身份驗證成功!!!");
} catch (AuthenticationException e) {
e.printStackTrace();
System.out.println("身份驗證失敗!!!!");
}
return subject;
}
}
在測試類中進行測試,我沒有使用junit進行測試,我是直接使用main方法測試
1.1測試subject.hasRole(String roleName) 返回值是boolean
public class TestRole {
public static void main(String[] args) {
Subject subject=ShiroUtil.login("shiro_role.ini", "yyt", "123");
//Subject subject=ShiroUtil.login("shiro_role.ini", "jack", "1234");
System.out.println(subject.hasRole("role2")?"有role2這個角色":"沒有role2這個角色");
}
}
控制檯的輸出是:有role2這個角色,
如果是換成了jack,控制檯輸出的是:沒有role2這個角色
1.2測試subject.hasRoles(List roles) 返回值是boolean[]
Subject subject=ShiroUtil.login("shiro_role.ini", "yyt", "123");
//Subject subject=ShiroUtil.login("shiro_role.ini", "jack", "1234");
boolean[] results=subject.hasRoles(Arrays.asList("role1","role2"));
for (boolean b : results) {
System.out.println(b);
}
使用者是yyt的時候,控制檯輸出的是:true,true,代表的是yyt擁有role1,role2這個角色
使用者是jack的時候,控制檯出去的是:true,false,代表的是jack使用者role1這個角色,但是沒有role2這個角色
1.3測試subject.hasAllRoles(List roles) 返回值是boolean
Subject subject=ShiroUtil.login("shiro_role.ini", "yyt", "123");
//Subject subject=ShiroUtil.login("shiro_role.ini", "jack", "1234");
System.out.println(subject.hasAllRoles(Arrays.asList("role1","role2"))?"有role2,role1這個角色":"role1,role2這個角色不全有");
使用者是yyt的時候,控制檯輸出的是:有role2,role1這個角色
使用者是jack的時候,控制檯出去的是:role1,role2這個角色不全有
1.4測試subject.checkRole(String roleName) 沒有返回值,假如驗證失敗,則會報錯:
org.apache.shiro.authz.UnauthorizedException: Subject does not have role [role2]
//Subject subject=ShiroUtil.login("shiro_role.ini", "yyt", "123");
Subject subject=ShiroUtil.login("shiro_role.ini", "jack", "1234");
subject.checkRole("role2");
1.5測試subject.checkRoles(String… roleIdentifiers) 可以傳入多個角色名稱,假如驗證失敗,則會報錯:
org.apache.shiro.authz.UnauthorizedException: Subject does not have role [role2]
Subject subject=ShiroUtil.login("shiro_role.ini", "yyt", "123");
//Subject subject=ShiroUtil.login("shiro_role.ini", "jack", "1234");
subject.checkRoles("role2","role1");
1.6測試subject.checkRoles(String… roleIdentifiers) 可以傳入多個角色名稱,假如驗證失敗,則會報錯:
org.apache.shiro.authz.UnauthorizedException: Subject does not have role [role2]
Subject subject=ShiroUtil.login("shiro_role.ini", "yyt", "123");
//Subject subject=ShiroUtil.login("shiro_role.ini", "jack", "1234");
subject.checkRoles(Arrays.asList("role1","role2"));
2.基於許可權的控制
配置檔案內容如下:shiro-permission.ini
[users]
yyt=123,role1,role2
jack=1234,role1
[roles]
role1=user:create,user:update
role2=user:create,user:delete
2.1測試subject.isPermitted(String name) 返回boolean
package com.kingsky;
import org.apache.shiro.subject.Subject;
public class TestPermission {
public static void main(String[] args) {
// Subject subject=ShiroUtil.login("shiro_role.ini", "yyt", "123");
Subject subject = ShiroUtil.login("shiro-permission.ini", "jack","1234");
boolean result= subject.isPermitted("user:create");
System.out.println(result?"有user:create這個許可權":"沒有user:create這個許可權");
}
}
控制檯輸出:有user:create這個許可權,假如許可權名稱改為:user:delete則輸出的沒有這個許可權
2.2測試subject.isPermittedAll(String… names) 返回boolean,代表是全有或者不全有這些許可權
// Subject subject=ShiroUtil.login("shiro_role.ini", "yyt", "123");
Subject subject = ShiroUtil.login("shiro-permission.ini", "jack","1234");
boolean result=subject.isPermittedAll("user:create","user:delete");
System.out.println(result?"有user:create,update這些許可權":"這些user:create,update許可權不全有");
控制檯輸出:有user:create,update這些許可權
假如修改許可權:user:delete,則會返回fase
2.3測試subject.isPermitted(String… names) 返回boolean[],對應的許可權是不是有
// Subject subject=ShiroUtil.login("shiro_role.ini", "yyt", "123");
Subject subject = ShiroUtil.login("shiro-permission.ini", "jack","1234");
boolean results[]=subject.isPermitted("user:create","user:delete");
for (boolean b : results) {
System.out.println(b);
}
控制檯輸出:true(代表user:create有許可權),false(代表user:delete沒有許可權)
2.4測試subject.checkPermission(String name);沒有返回值,但是驗證不成功則會報錯:
org.apache.shiro.authz.UnauthorizedException: Subject does not have permission [user:delete]
// Subject subject=ShiroUtil.login("shiro_role.ini", "yyt", "123");
Subject subject = ShiroUtil.login("shiro-permission.ini", "jack","1234");
subject.checkPermission("user:delete");
2.5測試subject.checkPermissions(Stirng… names);沒有返回值,但是驗證不成功則會報錯:
org.apache.shiro.authz.UnauthorizedException: Subject does not have permission [user:delete]
// Subject subject=ShiroUtil.login("shiro_role.ini", "yyt", "123");
Subject subject = ShiroUtil.login("shiro-permission.ini", "jack","1234");
subject.checkPermissions("user:create","user:update");
3.註解授權,jsp標籤授權
在JSP頁面通過相應的標籤完成:
<shiro:hasRole name="admin">
<!— 有許可權 —>
</shiro:hasRole>
4、Shiro對許可權字串缺失部分的處理
如“user:view”等價於“user:view:”;而“organization”等價於“organization:”或者“organization::”。可以這麼理解,這種方式實現了字首匹配。
另外如“user:”可以匹配如“user:delete”、“user:delete”可以匹配如“user:delete:1”、“user::1”可以匹配如“user:view:1”、“user”可以匹配“user:view”或“user:view:1”等。即可以匹配所有,不加可以進行字首匹配;但是如“:view”不能匹配“system:user:view”,需要使用“::view”,即字尾匹配必須指定字首(多個冒號就需要多個來匹配)。