鍍金池/ 教程/ Java/ Shiro快速入門教程
Shiro特點
Shiro Web應(yīng)用程序
Shiro教程
Shiro術(shù)語
Shiro是什么?
Shiro 10分鐘教程
Shiro快速入門教程

Shiro快速入門教程

[TOC]

通過這個快速和簡單的教程,理解開發(fā)人員如何在他們的應(yīng)用程序中使用Shiro。這個教程應(yīng)該能在10分鐘內(nèi)完成。

Apache Shiro是一個功能強大且易于使用的Java安全框架,為開發(fā)人員提供一個直觀而全面的身份驗證,授權(quán),加密和會話管理解決方案。

Apache Shiro它實現(xiàn)了管理應(yīng)用程序的安全性的所有方面,同時盡可能地避免錯誤。 它是建立在聲音接口驅(qū)動的設(shè)計和OO原則,使您能夠自定義行為。對于一切都有明智的默認,它是拿來即用的,因為應(yīng)用程序的安全性可以得到保證。

Apache Shiro能做什么?

Shiro能做的很多。但這里我們不想把QuickStart搞復雜了。如果想了解如何開始和為什么存在感到好奇,請參閱Shiro歷史和任務(wù)頁面。

注意:Shiro可以在任何環(huán)境中運行,從最簡單的命令行應(yīng)用程序到最大的企業(yè)Web和集群應(yīng)用程序,但是這里我們將使用一個簡單的“main”方法中的最簡單的例子來為這個QuickStart提供一個第一次的感覺。

下載Shiro

確保您已安裝JDK 1.6+Maven 3.0.3+

準備工作:

  1. 下載頁面下載最新的“源代碼分發(fā)”(Source Code Distribution)。 在這個例子中使用1.3.2發(fā)布版本。這里我把把它下載并保存為:F:\worksp\shiro\shiro-root-1.3.2-source-release.zip。
  1. 解壓縮源包,目錄如下所示:

    F:\worksp\shiro\shiro-root-1.3.2
    

  2. 進入quickstart目錄:F:\worksp\shiro\shiro-root-1.3.2\samples\quickstart

  3. 運行QuickStart示例程序,執(zhí)行以下命令:

    mvn compile exec:java
    

    提示:執(zhí)行上面命令,Maven會自動下載一些依懶包,根據(jù)你的網(wǎng)絡(luò)狀況決定完成的時間。

這個示例只打印出一些日志消息,讓你知道發(fā)生了什么,然后退出。 在閱讀這個快速入門的時候,請隨時查看samples/quickstart/src/main/java/Quickstart.java下的代碼。 更改該文件并運行上面的mvn compile exec:java命令,應(yīng)該會與您所愿那樣執(zhí)行。

第4步中,得到的結(jié)果(重點看日志輸出的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

上面引用的Quickstart.java文件包含了您熟悉API的所有代碼。 現(xiàn)在讓我們在這里分塊說明,這樣你就可以很容易地理解發(fā)生了什么。

在幾乎所有環(huán)境中,您可以通過以下調(diào)用獲取當前正在執(zhí)行的用戶:

Subject currentUser = SecurityUtils.getSubject();

使用SecurityUtils.[getSubject()](static/current/apidocs/org/apache/shiro/SecurityUtils.html#getSubject()), 獲得當前正在執(zhí)行的主題(Subject)。 主題僅僅是應(yīng)用程序用戶的安全特定的“視圖”。 我們實際上想把它稱為“User”,因為有太多的應(yīng)用程序自己的用戶類/框架與有現(xiàn)有的API會有些沖突,Shiro盡可能地排除這些沖突。 此外,在安全世界中,術(shù)語主題(Subject)實際上是公認的命名。

獨立應(yīng)用程序中的getSubject()調(diào)用可能會返回基于應(yīng)用程序特定位置中的用戶數(shù)據(jù)的主題,并且在服務(wù)器環(huán)境(例如:Web應(yīng)用程序)中,它基于與當前線程或傳入請求相關(guān)聯(lián)的用戶數(shù)據(jù)獲取主題。

現(xiàn)在有一個主題,你能用它做什么?

如果您想要用戶在應(yīng)用程序的當前會話期間使用戶可用,那么可以獲取其會話:

Session session = currentUser.getSession();
session.setAttribute( "someKey", "aValue" );

Session是一個Shiro特定的實例,它提供了大多數(shù)開發(fā)人員習慣的常規(guī)HttpSession,但有一些額外的好處和一些的區(qū)別:它不需要HTTP環(huán)境!

如果在Web應(yīng)用程序中部署,默認情況下會話將基于HttpSession。 但是,在非Web環(huán)境中,像這個簡單的Quickstart,Shiro將默認自動使用其企業(yè)會話管理。無論部署環(huán)境如何,您都可以在任何層次的應(yīng)用程序中使用相同的API。這是一個全新的應(yīng)用程序世界,因為任何需要會話的應(yīng)用程序不需要強制使用HttpSession或EJB有狀態(tài)會話Bean。 而且,任何客戶端技術(shù)現(xiàn)在都可以共享會話數(shù)據(jù)。

現(xiàn)在可以獲得一個主題和會話。真正有用的東西是檢查他們是否允許執(zhí)行某項操作,檢查角色和權(quán)限。

我們只能為已知用戶執(zhí)行這些檢查。上面的主題(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);
}

但是,如果他們的登錄嘗試失敗怎么辦? 您可以捕獲各種特定的異常,異常中告訴發(fā)生了什么,并允許您處理做出相應(yīng)的反應(yīng):

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?
}

有很多不同類型的異??筛鶕?jù)需要檢查匹配,或拋出自己的自定義的異常。 有關(guān)更多信息,請參閱:AuthenticationException JavaDoc。

提示:安全最佳做法是向用戶提供通用登錄失敗消息,因為我們不想幫助攻擊者試圖進入系統(tǒng)。

好的,所以到現(xiàn)在為止,我們有一個登錄用戶。接下來能做什么?

讓登錄用戶說他們是誰(獲取用戶身份):

//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." );
}

還可以查看他們是否有權(quán)對某種類型的實體執(zhí)行操作:

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.");
}

此外,我們可以執(zhí)行非常強大的實例級別權(quán)限檢查 - 查看用戶是否能夠訪問類型的特定實例:

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!");
}

最后,當用戶完成使用應(yīng)用程序時,他們可以執(zhí)行注銷:

currentUser.logout(); //removes all identifying information and invalidates their session too.

上面這些是在應(yīng)用程序開發(fā)人員級別使用Apache Shiro的核心。 雖然有一些非常復雜的東西在Shiro掩蓋下使這項工作如此優(yōu)雅。

但是你可能會問:“誰負責在登錄期間獲取用戶數(shù)據(jù)(用戶名和密碼,角色和權(quán)限等),以及誰在運行期間實際執(zhí)行這些安全檢查?”嗯, Shiro調(diào)用Realm并將該Realm插入Shiro的配置。

但是,如何配置Realm主要取決于運行時環(huán)境。 例如,如果您運行獨立應(yīng)用程序,或者您有基于Web的應(yīng)用程序,或基于Spring或JEE容器的應(yīng)用程序或其組合。 這種類型的配置不在本QuickStart的范圍之內(nèi),因為QuickStart的目的是讓您輕松使用API和理解Shiro的基本概念。