第六章 Realm及相關物件——《跟我學Shiro》
ection;然後通過其getPrimaryPrincipal獲取PrimaryPrincipal。
Java程式碼- Set<String> realmNames = princialCollection.getRealmNames();
獲取所有身份驗證成功的Realm名字。
Java程式碼- Set<Object> principals = princialCollection.asSet(); //asList和asSet的結果一樣
將身份資訊轉換為Set/List,即使轉換為List,也是先轉換為Set再完成的。
Java程式碼- Collection<User> users = princialCollection.fromRealm("c");
根據Realm名字獲取身份,因為Realm名字可以重複,所以可能多個身份,建議Realm名字儘量不要重複。
6.4 AuthorizationInfo
AuthorizationInfo用於聚合授權資訊的:
Java程式碼- public interface AuthorizationInfo extends Serializable {
- Collection<String> getRoles(); //獲取角色字串資訊
- Collection<String> getStringPermissions(); //獲取許可權字串資訊
- Collection<Permission> getObjectPermissions(); //獲取Permission物件資訊
- }
當我們使用AuthorizingRealm時,如果身份驗證成功,在進行授權時就通過doGetAuthorizationInfo方法獲取角色/許可權資訊用於授權驗證。
Shiro提供了一個實現SimpleAuthorizationInfo,大多數時候使用這個即可。
對於Account及SimpleAccount,之前的【6.3 AuthenticationInfo】已經介紹過了,用於SimpleAccountRealm子類,實現動態角色/許可權維護的。
6.5 Subject
Subject是Shiro的核心物件,基本所有身份驗證、授權都是通過Subject完成。
1、身份資訊獲取
Java程式碼- Object getPrincipal(); //Primary Principal
- PrincipalCollection getPrincipals(); // PrincipalCollection
2、身份驗證
Java程式碼- void login(AuthenticationToken token) throws AuthenticationException;
- boolean isAuthenticated();
- boolean isRemembered();
通過login登入,如果登入失敗將丟擲相應的AuthenticationException,如果登入成功呼叫isAuthenticated就會返回true,即已經通過身份驗證;如果isRemembered返回true,表示是通過記住我功能登入的而不是呼叫login方法登入的。isAuthenticated/isRemembered是互斥的,即如果其中一個返回true,另一個返回false。
3、角色授權驗證
Java程式碼- boolean hasRole(String roleIdentifier);
- boolean[] hasRoles(List<String> roleIdentifiers);
- boolean hasAllRoles(Collection<String> roleIdentifiers);
- void checkRole(String roleIdentifier) throws AuthorizationException;
- void checkRoles(Collection<String> roleIdentifiers) throws AuthorizationException;
- void checkRoles(String... roleIdentifiers) throws AuthorizationException;
hasRole*進行角色驗證,驗證後返回true/false;而checkRole*驗證失敗時丟擲AuthorizationException異常。
4、許可權授權驗證
Java程式碼- boolean isPermitted(String permission);
- boolean isPermitted(Permission permission);
- boolean[] isPermitted(String... permissions);
- boolean[] isPermitted(List<Permission> permissions);
- boolean isPermittedAll(String... permissions);
- boolean isPermittedAll(Collection<Permission> permissions);
- void checkPermission(String permission) throws AuthorizationException;
- void checkPermission(Permission permission) throws AuthorizationException;
- void checkPermissions(String... permissions) throws AuthorizationException;
- void checkPermissions(Collection<Permission> permissions) throws AuthorizationException;
isPermitted*進行許可權驗證,驗證後返回true/false;而checkPermission*驗證失敗時丟擲AuthorizationException。
5、會話
Java程式碼- Session getSession(); //相當於getSession(true)
- Session getSession(boolean create);
類似於Web中的會話。如果登入成功就相當於建立了會話,接著可以使用getSession獲取;如果create=false如果沒有會話將返回null,而create=true如果沒有會話會強制建立一個。
6、退出
Java程式碼- void logout();
7、RunAs
Java程式碼- void runAs(PrincipalCollection principals) throws NullPointerException, IllegalStateException;
- boolean isRunAs();
- PrincipalCollection getPreviousPrincipals();
- PrincipalCollection releaseRunAs();
RunAs即實現“允許A假設為B身份進行訪問”;通過呼叫subject.runAs(b)進行訪問;接著呼叫subject.getPrincipals將獲取到B的身份;此時呼叫isRunAs將返回true;而a的身份需要通過subject. getPreviousPrincipals獲取;如果不需要RunAs了呼叫subject. releaseRunAs即可。
8、多執行緒
Java程式碼- <V> V execute(Callable<V> callable) throws ExecutionException;
- void execute(Runnable runnable);
- <V> Callable<V> associateWith(Callable<V> callable);
- Runnable associateWith(Runnable runnable);
實現執行緒之間的Subject傳播,因為Subject是執行緒繫結的;因此在多執行緒執行中需要傳播到相應的執行緒才能獲取到相應的Subject。最簡單的辦法就是通過execute(runnable/callable例項)直接呼叫;或者通過associateWith(runnable/callable例項)得到一個包裝後的例項;它們都是通過:1、把當前執行緒的Subject繫結過去;2、線上程執行結束後自動釋放。
Subject自己不會實現相應的身份驗證/授權邏輯,而是通過DelegatingSubject委託給SecurityManager實現;及可以理解為Subject是一個面門。
對於Subject的構建一般沒必要我們去建立;一般通過SecurityUtils.getSubject()獲取:
Java程式碼- public static Subject getSubject() {
- Subject subject = ThreadContext.getSubject();
- if (subject == null) {
- subject = (new Subject.Builder()).buildSubject();
- ThreadContext.bind(subject);
- }
- return subject;
- }
即首先檢視當前執行緒是否綁定了Subject,如果沒有通過Subject.Builder構建一個然後繫結到現場返回。
如果想自定義建立,可以通過:
Java程式碼- new Subject.Builder().principals(身份).authenticated(true/false).buildSubject()
這種可以建立相應的Subject例項了,然後自己繫結到執行緒即可。在new Builder()時如果沒有傳入SecurityManager,自動呼叫SecurityUtils.getSecurityManager獲取;也可以自己傳入一個例項。
對於Subject我們一般這麼使用:
1、身份驗證(login)
2、授權(hasRole*/isPermitted*或checkRole*/checkPermission*)
3、將相應的資料儲存到會話(Session)
4、切換身份(RunAs)/多執行緒身份傳播
5、退出
而我們必須的功能就是1、2、5。到目前為止我們就可以使用Shiro進行應用程式的安全控制了,但是還是缺少如對Web驗證、Java方法驗證等的一些簡化實現。