<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ThinkChat2.0新版上線,更智能更精彩,支持會話、畫圖、視頻、閱讀、搜索等,送10W Token,即刻開啟你的AI之旅 廣告
                # 14. Custom Subjects 自定義 Subject # 14. Custom Subjects 自定義 Subject 毫無疑問,在 Apache Shiro 中最重要的概念就是 Subject。 'Subject' 僅僅是一個安全術語,是指應用程序用戶的特定安全的“視圖”。一個 Shiro Subject 實例代表了一個單一應用程序用戶的安全狀態和操作。 這些操作包括: - authentication(login) - authorization(access control) - session access - logout 我們原本希望把它稱為"User"由于這樣“很有意義”,但是我們決定不這樣做:太多的應用程序現有的 API 已經有自己的 User classes/frameworks,我們不希望和這些起沖突。此外,在安全領域,"Subject" 這一詞實際上是公認的術語。 Shiro 的 API 為應用程序提供 Subject 為中心的編程范式支持。當編碼應用程序邏輯時,大多數應用程序開發人員想知道誰才是當前正在執行的用戶。雖然應用程序通常能夠通過它們自己的機制( UserService 等)來查找任何用戶,但涉及到安全性時,最重要的問題是“誰才是當前的用戶?”。 雖然通過使用 SecurityManager 可以捕獲任何 Subject,但只有基于當前 用戶/Subject 的應用程序代碼更自然,更直觀。 ## The Currently Executing Subject 當前執行的Subject 幾乎在所有環境下,你能夠獲得當前執行的 Subject 通過使用 ``` org.apache.shiro.SecurityUtils:Subject currentUser ``` getSubject() 方法調用一個獨立的應用程序,該應用程序可以返回一個在應用程序特有位置上基于用戶數據的Subject,在服務器環境中(如,Web 應用程序),它基于與當前線程或傳入的請求相關的用戶數據上獲得 Subject 。 當你獲得了當前的 Subject 后,你能夠拿它做些什么? 如果你想在他們當前的 session 中使事情對用戶變得可用,你可得的他們的 session: ``` Session session = currentUser.getSession(); session.setAttribute( "someKey", "aValue" ); ``` Session 是一個 Shiro 的具體實例,它提供了大多數你經常要和HttpSessions 用到的東西,但有一些額外的好處和一個很大的區別:它不需要一個 HTTP 環境! 如果在 Web 應用程序內部部署,默認的 Session 將會是基于HttpSession 的。但是,在一個非 Web 環境中,像這個簡單的 Quickstart,Shiro 將會默認自動地使用它的 Enterprise Session Management。這意味著你可以在你的應用程序中使用相同的 API,在任何層,無論部署環境。這打開了應用程序的全新世界,由于任何需要 session 的應用程序不再被強迫使用 HttpSession 或 EJB Stateful Session Beans。而且,任何客戶端技術現在能夠共享會話數據。 所以,你現在可以獲取一個 Subject 以及他們的 Session。對于真正有用的東西像檢查會怎么樣呢,如果他們被允許做某些事——如對角色和權限的檢查? 嗯,我只能對已知的用戶做這些檢查。我們的 Subject 實例代表了當前的用戶,但誰又是實際上的當前用戶呢?呃,他們都是匿名的——也就是說,直到他們至少登錄一次。那么,讓我們像下面這樣做: ``` if ( !currentUser.isAuthenticated() ) { //collect user principals and credentials in a gui specific manner //such as username/password html form, X509 certificate, OpenID, etc. //We'll use the username/password example here since it is the most common. //(do you know what movie this is from? ;) UsernamePasswordToken token = new UsernamePasswordToken("lonestarr", "vespa"); //this is all you have to do to support 'remember me' (no config - built in!): token.setRememberMe(true); currentUser.login(token); } ``` 那就是了!它再簡單不過了。 但如果他們的登錄嘗試失敗了會怎么樣?你可以捕獲各種各樣的具體的異常來告訴你到底發生了什么: ``` try { currentUser.login( token ); //if no exception, that's it, we're done! } catch ( UnknownAccountException uae ) { //username wasn't in the system, show them an error message? } catch ( IncorrectCredentialsException ice ) { //password didn't match, try again? } catch ( LockedAccountException lae ) { //account for that username is locked - can't login. Show them a message? } ... more types exceptions to check if you want ... } catch ( AuthenticationException ae ) { //unexpected condition - error? } ``` 你,作為 應用程序/GUI 開發人員,可以基于異常選擇是否顯示消息給終端用戶(例如,“在系統中沒有與該用戶名對應的帳戶。”)。有許多不同種類的異常供你檢查,或者你可以拋出你自己自定義的異常,這些異常可能是Shiro 還未提供的。有關詳情,請查看AuthenticationException 的[JavaDoc](http://www.jsecurity.org/api/org/jsecurity/authc/AuthenticationException.html)。 好了,現在,我們有了一個登錄的用戶,我們還有什么可以做的呢? 比方說,他們是誰: ``` //print their identifying principal (in this case, a username): log.info( "User [" + currentUser.getPrincipal() + "] logged in successfully." ); ``` 我們還可以測試他們是否有特定的角色: ``` if ( currentUser.hasRole( "schwartz" ) ) { log.info("May the Schwartz be with you!" ); } else { log.info( "Hello, mere mortal." ); } ``` 我們還能夠判斷他們是否有[權限](http://shiro.apache.org/permissions.html)對一個確定類型的實體進行操作 ``` if ( currentUser.isPermitted( "lightsaber:weild" ) ) { log.info("You may use a lightsaber ring. Use it wisely."); } else { log.info("Sorry, lightsaber rings are for schwartz masters only."); } ``` 此外,我們可以執行一個非常強大的實例級權限檢查——它能夠判斷用戶是否能夠訪問一個類型的具體實例: ``` if ( currentUser.isPermitted( "winnebago:drive:eagle5" ) ) { log.info("You are permitted to 'drive' the 'winnebago' with license plate (id) 'eagle5'. " + "Here are the keys - have fun!"); } else { log.info("Sorry, you aren't allowed to drive the 'eagle5' winnebago!"); } ``` 小菜一碟,對吧? 最后,當用戶完成了對應用程序的使用時,他們可以注銷: ``` currentUser.logout(); //removes all identifying information and invalidates their session too. ``` 這個簡單的API 包含了 90% 的 Shiro 終端用戶在使用 Shiro 時將會處理的東西。 ## Custom Subject Instances 自定義 Subject 實例 Shiro 1.0 中添加了一個新特性,能夠在特殊情況下構造 自定義/臨時 的subject 實例。 *只在特殊情況下使用!* *你應該總是通過調用 SubjectUtils.getSubject() 來獲得當前正在執行的 Subject; 創建自定義的 Subject 實例只應在特殊情況下進行。* 當一些“特殊情況”是,這是可以很有用的: - 系統啟動/引導——當沒有用戶月系統交互時,代碼應該作為一'system'或daemon 用戶來執行。創建 Subject實例來代表一個特定的用戶是值得的,這樣引導代碼能夠以該用戶(如admin)來執行。 鼓勵這種做法是由于它能保證 utility/system 代碼作為一個普通用戶以同樣的方式執行,以確保代碼是一致的。 這使得代碼更易于維護,因為你不必擔心 system/daemon 方案的自定義代碼塊。 - 集成測試——你可能想創建 Subject 實例,在必要時可以在集成測試中使用。請參閱[測試](13.%20Testing%20%E6%B5%8B%E8%AF%95.md)文檔獲取更多的內容。 - Daemon/background 進程的工作——當一個 daemon 或 background 進程執行時,它可能需要作為一個特定的用戶來執行。 *如果你已經有一個 Subject 的實例,并希望它提供給其他線程,你應該使用 `Subject.associateWith*` 方法,而不是創建一個新的Subject 實例。\* 好了,假設你仍然需要創建自定義的Subject 實例的情況下,讓我們看看如何來做: ### Subject.Builder Subject.Builder 被制定得非常容易創建 Subject 實例,而無需知道構造細節。 Builder 最簡單的用法是構造一個匿名的,session-less(無會話) Subject 的實例。 ``` Subject subject = new Subject.Builder().buildSubject() ``` 上面所展示的默認的Subject.Builder 無參構造函數將通過SecurityUtils.getSubject() 方法使用應用程序當前可訪問的 SecurityManager 。你也可以指定被額外的構造函數使用的SecurityManager 實例,如果你需要的話: ``` SecurityManager securityManager = //acquired from somewhere Subject subject = new Subject.Builder(securityManager).buildSubject(); ``` 所有其他的 Subject.Builder 方法可以在 buildSubject()方法之前被調用,它們來提供關于如何構造 Subject 實例的上下文。例如,假如你擁有一個 session ID ,想取得“擁有”該 session 的Subject(假設該 session 存在且未過期): ``` Serializable sessionId = //acquired from somewhere Subject subject = new Subject.Builder().sessionId(sessionId).buildSubject(); ``` 同樣地,如你想創建一個Subject 實例來反映一個確定的身份: ``` Object userIdentity = //a long ID or String username, or whatever the "myRealm" requires String realmName = "myRealm"; PrincipalCollection principals = new SimplePrincipalCollection(userIdentity, realmName); Subject subject = new Subject.Builder().principals(principals).buildSubject(); ``` 然后,你可以使用構造的 Subject 實例,如預期一樣對它進行調用。但請注意: 構造的 Subject 實例不會由于應用程序(線程)的進一步使用而自動地綁定到應用程序(線程)。如果你想讓它對于任何代碼都能夠方便地調用SecurityUtils.getSubject(),你必須確保創建好的 Subject 有一個線程與之關聯。 ### Thread Association 線程關聯 如上所述,只是構建一個 Subject 實例,并不與一個線程相關聯——一個普通的必要條件是在線程執行期間任何對 SecurityUtils.getSubject() 的調用是否能正常工作。確保一個線程與一個 Subject 關聯有三種途徑: - Automatic Association(自動關聯)—— 通過 Sujbect.execute\* 方法執行一個Callable 或Runnable 方法會自動地綁定和解除綁定到線程的Subject,在Callable/Runnable 異常的前后。 - Manual Association(手動關聯)——你可以在當前執行的線程中手動地對Subject 實例進行綁定和解除綁定。這通常對框架開發人員非常有用。 - Different Thread(不同的線程)——通過調用Subject.associateWith\* 方法將 Callable 或 Runnable 方法關聯到 Subject,然后返回的 Callable/Runnable 方法在另一個線程中被執行。如果你需要為Subject 在另一個線程上執行工作的話,這是首選的方法。 了解線程關聯最重要的是,兩件事情必須始終發生: 1. Subject 綁定到線程,所以它在線程的所有執行點都是可用的。Shiro 做到這點通過它的 ThreadState 機制,該機制是在 ThreadLocal 上的一個抽象。 2. Subject 將在某點解除綁定,即使線程的執行結果是錯誤的。這將確保線程保持干凈,并在pooled/reusable 線程環境中清除任何之前的Subject 狀態。 這些原則保證在上述三個機制中發生。接下來闡述它們的用法。 #### Automatic Association 自動關聯 如果你只需要一個 Subject 暫時與當前的線程相關聯,同時你希望線程綁定和清理自動發生,Subject 的 Callable 或 Runnable 的直接執行正是你所需要的。在 Subject.execute 調用返回后,當前線程被保證當前狀態與執行前的狀態是一樣的。這個機制是這三個中使用最廣泛的。 例如,讓我們假定你有一些邏輯在系統啟動時需要執行。你希望作為一個特定用戶執行代碼塊,但一旦邏輯完成后,你想確保 線程/環境 自動地恢復到正常。你可以通過調用 Subject.execute\* 方法來做到: ``` Subject subject = //build or acquire subject subject.execute( new Runnable() { public void run() { //subject is 'bound' to the current thread now //any SecurityUtils.getSubject() calls in any //code called from here will work } }); //At this point, the Subject is no longer associated //with the current thread and everything is as it was before ``` 當然,Callable 的實例也能夠被支持,所以你能夠擁有返回值并捕獲異常: ``` Subject subject = //build or acquire subject MyResult result = subject.execute( new Callable<MyResult>() { public MyResult call() throws Exception { //subject is 'bound' to the current thread now //any SecurityUtils.getSubject() calls in any //code called from here will work ... //finish logic as this Subject ... return myResult; } }); //At this point, the Subject is no longer associated //with the current thread and everything is as it was before ``` 這種方法在框架開發中也是很有用的。例如,Shiro 對 secure Spring remoting 的支持確保了遠程調用能夠作為一個特 定的 Subject 來執行: ``` Subject.Builder builder = new Subject.Builder(); //populate the builder's attributes based on the incoming RemoteInvocation ... Subject subject = builder.buildSubject(); return subject.execute(new Callable() { public Object call() throws Exception { return invoke(invocation, targetObject); } }); ``` #### Manual Association 手動關聯 雖然 Subject.execute\* 方法能夠在它們返回后自動地清理線程的狀態,但有可能在一些情況下,你想自己管理 ThreadState。當結合 w/Shiro 時,這幾乎總是在框架開發層次使用,但它很少在 bootstrap/daemon 情景下使用(上面 Subject.execute(callable) 例子使用得更為頻繁)。 *Guarantee Cleanup* *關于這一機制最重要的是,你必須一直保證當前的線程在邏輯執行完后被清理,以確保在一個可重復使用或線程池的環境中沒有一個線程狀態腐化。* 最好的做法是在try/finally 塊保證清理: ``` Subject subject = new Subject.Builder()... ThreadState threadState = new SubjectThreadState(subject); threadState.bind(); try { //execute work as the built Subject } finally { //ensure any state is cleaned so the thread won't be //corrupt in a reusable or pooled thread environment threadState.clear(); } ``` 有趣的是,這正是 Subject.execute\* 方法實際上所做的——它們只是在Callable 或 Runnable 執行前后自動地執行這個邏輯。Shiro 的 ShiroFilter 為 Web 應用程序執行幾乎相同的邏輯(ShiroFilter 使用 Web 特定的 ThreadState 的實現,超出了本節的范圍) *Web Use* *不要在一個處理 Web 請求的進程中使用上述 ThreadState 代碼示例。 Web 特定的 ThreadState 的實現使用 Web 請求代替。相反,確保ShiroFilter 攔截 Web 請求以確保 Subject 的 building/binding/cleanup 能夠好好的完成。* #### A Different Thread 如果你有一個 Callable 或 Runnable 實例要以 Subject 來執行,你將自己執行 Callable 或 Runnable(或這將它移交給線程池或執行者或ExcutorService),你應該使用 Subject.associateWith\* 方法。這些方法確保在最終執行的線程中保 留 Subject,且該 Subject 是可訪問的。 Callable 例子: ``` Subject subject = new Subject.Builder()... Callable work = //build/acquire a Callable instance. //associate the work with the built subject so SecurityUtils.getSubject() calls works properly: work = subject.associateWith(work); ExecutorService executorService = new java.util.concurrent.Executors.newCachedThreadPool(); //execute the work on a different thread as the built Subject: executor.execute(work); ``` Runnable 例子: ``` Subject subject = new Subject.Builder()... Runnable work = //build/acquire a Runnable instance. //associate the work with the built subject so SecurityUtils.getSubject() calls works properly: work = subject.associateWith(work); Executor executor = new java.util.concurrent.Executors.newCachedThreadPool(); //execute the work on a different thread as the built Subject: executor.execute(work); ``` *Automatic Cleanup* *associateWith 方法自動執行必要的線程清理,以取保現在在線程池環境中的clean。* ## 為文檔加把手 我們希望這篇文檔可以幫助你使用 Apache Shiro 進行工作,社區一直在不斷地完善和擴展文檔,如果你希望幫助 Shiro 項目,請在你認為需要的地方考慮更正、擴展或添加文檔,你提供的任何點滴幫助都將擴充社區并且提升 Shiro。 提供你的文檔的最簡單的途徑是將它發送到用戶[論壇](http://shiro-user.582556.n2.nabble.com/)或[郵件列表](http://shiro.apache.org/mailing-lists.html) *譯者注:*如果對本中文翻譯有疑議的或發現勘誤歡迎指正,[點此](https://github.com/waylau/apache-shiro-1.2.x-reference/issues)提問。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看