通過這個快速和簡單的教學,理解開發人員如何在他們的應用程式中使用Shiro
。這個教學應該能在10
分鐘內完成。
Apache Shiro是一個功能強大且易於使用的Java安全框架,為開發人員提供一個直觀而全面的身份驗證,授權,加密和對談管理解決方案。
Apache Shiro它實現了管理應用程式的安全性的所有方面,同時盡可能地避免錯誤。 它是建立在聲音介面驅動的設計和OO原則,使您能夠自定義行為。對於一切都有明智的預設,它是拿來即用的,因為應用程式的安全性可以得到保證。
Apache Shiro能做什麼?
Shiro能做的很多。但這裡我們不想把QuickStart
搞複雜了。如果想了解如何開始和為什麼存在感到好奇,請參閱Shiro歷史和任務頁面。
注意:Shiro可以在任何環境中執行,從最簡單的命令列應用程式到最大的企業Web和叢集應用程式,但是這裡我們將使用一個簡單的「main」方法中的最簡單的例子來為這個QuickStart提供一個第一次的感覺。
確保您已安裝JDK 1.6+
和Maven 3.0.3+
。
準備工作:
Source Code Distribution
)。 在這個例子中使用1.3.2
發布版本。這裡我把把它下載並儲存為:F:\worksp\shiro\shiro-root-1.3.2-source-release.zip
。解壓縮源包,目錄如下所示:
F:\worksp\shiro\shiro-root-1.3.2
進入quickstart
目錄:F:\worksp\shiro\shiro-root-1.3.2\samples\quickstart
:
執行QuickStart
範例程式,執行以下命令:
mvn compile exec:java
提示:執行上面命令,Maven會自動下載一些依懶包,根據你的網路狀況決定完成的時間。
這個範例只列印出一些紀錄檔訊息,讓你知道發生了什麼,然後退出。 在閱讀這個快速入門的時候,請隨時檢視samples/quickstart/src/main/java/Quickstart.java
下的程式碼。 更改該檔案並執行上面的mvn compile exec:java
命令,應該會與您所願那樣執行。
第4步中,得到的結果(重點看紀錄檔輸出的INFO
)如下-
......
2017-03-14 23:32:37,357 INFO [Quickstart] - User [lonestarr] logged in successfully.
2017-03-14 23:32:37,357 TRACE [org.apache.shiro.subject.support.DelegatingSubject] - attempting to get session; create = false; session is null = false; session has id = true
2017-03-14 23:32:37,357 TRACE [org.apache.shiro.session.mgt.AbstractValidatingSessionManager] - Attempting to retrieve session with key org.apache.shiro.session.mgt.DefaultSessionKey@2bfc7259
2017-03-14 23:32:37,357 TRACE [org.apache.shiro.subject.support.DelegatingSubject] - attempting to get session; create = false; session is null = false; session has id = true
2017-03-14 23:32:37,357 TRACE [org.apache.shiro.session.mgt.AbstractValidatingSessionManager] - Attempting to retrieve session with key org.apache.shiro.session.mgt.DefaultSessionKey@2bfc7259
2017-03-14 23:32:37,373 TRACE [org.apache.shiro.realm.AuthorizingRealm] - Retrieving AuthorizationInfo for principals [lonestarr]
2017-03-14 23:32:37,373 INFO [Quickstart] - May the Schwartz be with you!
2017-03-14 23:32:37,373 TRACE [org.apache.shiro.subject.support.DelegatingSubject] - attempting to get session; create = false; session is null = false; session has id = true
2017-03-14 23:32:37,373 TRACE [org.apache.shiro.session.mgt.AbstractValidatingSessionManager] - Attempting to retrieve session with key org.apache.shiro.session.mgt.DefaultSessionKey@2bfc7259
2017-03-14 23:32:37,373 TRACE [org.apache.shiro.subject.support.DelegatingSubject] - attempting to get session; create = false; session is null = false; session has id = true
2017-03-14 23:32:37,373 TRACE [org.apache.shiro.session.mgt.AbstractValidatingSessionManager] - Attempting to retrieve session with key org.apache.shiro.session.mgt.DefaultSessionKey@2bfc7259
2017-03-14 23:32:37,388 TRACE [org.apache.shiro.realm.AuthorizingRealm] - Retrieving AuthorizationInfo for principals [lonestarr]
2017-03-14 23:32:37,388 INFO [Quickstart] - You may use a lightsaber ring. Use it wisely.
2017-03-14 23:32:37,388 TRACE [org.apache.shiro.subject.support.DelegatingSubject] - attempting to get session; create = false; session is null = false; session has id = true
2017-03-14 23:32:37,388 TRACE [org.apache.shiro.session.mgt.AbstractValidatingSessionManager] - Attempting to retrieve session with key org.apache.shiro.session.mgt.DefaultSessionKey@2bfc7259
2017-03-14 23:32:37,388 TRACE [org.apache.shiro.subject.support.DelegatingSubject] - attempting to get session; create = false; session is null = false; session has id = true
2017-03-14 23:32:37,388 TRACE [org.apache.shiro.session.mgt.AbstractValidatingSessionManager] - Attempting to retrieve session with key org.apache.shiro.session.mgt.DefaultSessionKey@2bfc7259
2017-03-14 23:32:37,404 TRACE [org.apache.shiro.realm.AuthorizingRealm] - Retrieving AuthorizationInfo for principals [lonestarr]
2017-03-14 23:32:37,404 INFO [Quickstart] - You are permitted to 'drive' the winnebago with license plate (id) 'eagle5'. Here are the keys - have fun!
2017-03-14 23:32:37,404 TRACE [org.apache.shiro.subject.support.DelegatingSubject] - attempting to get session; create = false; session is null = false; session has id = true
2017-03-14 23:32:37,404 TRACE [org.apache.shiro.session.mgt.AbstractValidatingSessionManager] - Attempting to retrieve session with key org.apache.shiro.session.mgt.DefaultSessionKey@2bfc7259
2017-03-14 23:32:37,404 TRACE [org.apache.shiro.subject.support.DelegatingSubject] - attempting to get session; create = false; session is null = false; session has id = true
2017-03-14 23:32:37,419 TRACE [org.apache.shiro.session.mgt.AbstractValidatingSessionManager] - Attempting to retrieve session with key org.apache.shiro.session.mgt.DefaultSessionKey@2bfc7259
2017-03-14 23:32:37,419 DEBUG [org.apache.shiro.mgt.DefaultSecurityManager] - Logging out subject with primary principal lonestarr
2017-03-14 23:32:37,419 TRACE [org.apache.shiro.realm.CachingRealm] - Cleared cache entries for account with principals [lonestarr]
2017-03-14 23:32:37,419 TRACE [org.apache.shiro.subject.support.DelegatingSubject] - attempting to get session; create = false; session is null = false; session has id = true
2017-03-14 23:32:37,419 TRACE [org.apache.shiro.session.mgt.AbstractValidatingSessionManager] - Attempting to retrieve session with key org.apache.shiro.session.mgt.DefaultSessionKey@2bfc7259
2017-03-14 23:32:37,435 TRACE [org.apache.shiro.session.mgt.AbstractValidatingSessionManager] - Attempting to retrieve session with key org.apache.shiro.session.mgt.DefaultSessionKey@2bfc7259
2017-03-14 23:32:37,435 TRACE [org.apache.shiro.subject.support.DelegatingSubject] - attempting to get session; create = false; session is null = false; session has id = true
2017-03-14 23:32:37,435 TRACE [org.apache.shiro.session.mgt.AbstractValidatingSessionManager] - Attempting to retrieve session with key org.apache.shiro.session.mgt.DefaultSessionKey@2bfc7259
2017-03-14 23:32:37,435 DEBUG [org.apache.shiro.session.mgt.AbstractSessionManager] - Stopping session with id [21659e1a-05b2-4b0e-9745-996a825bdbff]
F:\worksp\shiro\shiro-root-1.3.2\samples\quickstart>
上面參照的Quickstart.java
檔案包含了您熟悉API的所有程式碼。 現在讓我們在這裡分塊說明,這樣你就可以很容易地理解發生了什麼。
在幾乎所有環境中,您可以通過以下呼叫獲取當前正在執行的使用者:
Subject currentUser = SecurityUtils.getSubject();
使用SecurityUtils.[getSubject()](static/current/apidocs/org/apache/shiro/SecurityUtils.html#getSubject())
, 獲得當前正在執行的主題(Subject
)。 主題僅僅是應用程式使用者的安全特定的「檢視」。 我們實際上想把它稱為「User
」,因為有太多的應用程式自己的使用者類/框架與有現有的API會有些衝突,Shiro盡可能地排除這些衝突。 此外,在安全世界中,術語主題(Subject
)實際上是公認的命名。
獨立應用程式中的getSubject()
呼叫可能會返回基於應用程式特定位置中的使用者資料的主題,並且在伺服器環境(例如:Web應用程式)中,它基於與當前執行緒或傳入請求相關聯的使用者資料獲取主題。
現在有一個主題,你能用它做什麼?
如果您想要使用者在應用程式的當前對談期間使使用者可用,那麼可以獲取其對談:
Session session = currentUser.getSession();
session.setAttribute( "someKey", "aValue" );
Session
是一個Shiro特定的範例,它提供了大多數開發人員習慣的常規HttpSession
,但有一些額外的好處和一些的區別:它不需要HTTP環境!
如果在Web應用程式中部署,預設情況下對談將基於HttpSession
。 但是,在非Web環境中,像這個簡單的Quickstart
,Shiro將預設自動使用其企業對談管理。無論部署環境如何,您都可以在任何層次的應用程式中使用相同的API。這是一個全新的應用程式世界,因為任何需要對談的應用程式不需要強制使用HttpSession
或EJB有狀態對談Bean。 而且,任何用戶端技術現在都可以共用對談資料。
現在可以獲得一個主題和對談。真正有用的東西是檢查他們是否允許執行某項操作,檢查角色和許可權。
我們只能為已知使用者執行這些檢查。上面的主題(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?
}
有很多不同型別的異常可根據需要檢查匹配,或丟擲自己的自定義的異常。 有關更多資訊,請參閱:AuthenticationException JavaDoc。
提示:安全最佳做法是向使用者提供通用登入失敗訊息,因為我們不想幫助攻擊者試圖進入系統。
好的,所以到現在為止,我們有一個登入使用者。接下來能做什麼?
讓登入使用者說他們是誰(獲取使用者身份):
//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." );
}
還可以檢視他們是否有權對某種型別的實體執行操作:
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.
上面這些是在應用程式開發人員級別使用Apache Shiro的核心。 雖然有一些非常複雜的東西在Shiro掩蓋下使這項工作如此優雅。
但是你可能會問:「誰負責在登入期間獲取使用者資料(使用者名和密碼,角色和許可權等),以及誰在執行期間實際執行這些安全檢查?」嗯, Shiro呼叫Realm並將該Realm插入Shiro的組態。
但是,如何組態Realm
主要取決於執行時環境。 例如,如果您執行獨立應用程式,或者您有基於Web的應用程式,或基於Spring或JEE容器的應用程式或其組合。 這種型別的組態不在本QuickStart
的範圍之內,因為QuickStart
的目的是讓您輕鬆使用API和理解Shiro的基本概念。