Apache Shiro 安全框架入門系列—4-親手打造第一個Shiro應用

前言

文本是這個系列的第4篇:

“第一個Apache Shiro應用”

前3篇分別是:

“Apache Shiro 安全框架入門系列—1-框架概覽”;

“Apache Shiro 安全框架入門系列—2-詳解核心術語”;

“Apache Shiro 10分鐘入門教程”。

如果您是Apache Shiro的新手,這個簡短的教程將向您展示如何設置基於Apache Shiro的初始的且非常簡單的安全應用。 我們將一路討論Shiro的核心概念,以幫助您熟悉Shiro的設計和API。

1)Apache Shiro的Git倉庫中:

https://github.com/apache/shiro/tree/master/samples/quickstart

2)源碼發行包:在Apache Shiro的源代碼發行包的samples/quickstart目錄中。 源代碼發行包可從"這裡"(http://shiro.apache.org/download.html)頁面獲得。

1. 設置

在這個簡單的例子中,我們將創建一個非常簡單的命令行應用程序,它將運行並快速退出,這樣只是讓您體會Shiro的API。

注:對任何應用——Apache Shiro的設計從一開始就支持任何應用程序,無論從最小的命令行應用程序還是到最大的集群Web應用程序。 儘管我們為本教程創建了一個簡單的應用程序,但請注意,無論您的應用程序的創建方式或部署方式如何,都會應用相同的使用模式。

本教程需要Java 1.5或更高版本。 我們也將使用Apache Maven作為我們的構建工具,但當然這不是使用Apache Shiro所必需的。 您可能會獲取Shiro的所有.jars包,並將它們以您喜歡的任何方式整合到您的應用程序中,例如使用Apache Ant和Ivy。

對於本教程,請確保您使用的是Maven 2.2.1或更高版本。 您應該能夠在命令提示符下鍵入mvn --version並查看是否與以下的內容類似。

1- 檢查Maven安裝情況

在不同的平臺上,打開命令行終端,輸入如下命令:

mvn –-version或者mvn –v回車,可以看到類似如下信息:

Apache Shiro 安全框架入門系列—4-親手打造第一個Shiro應用

現在,在文件系統上創建一個新目錄,例如shiro-tutorial,並將以下Maven pom.xml文件保存在該目錄中。

2- 構建pom.xml

我這裡在window平臺創建目錄如下:E:\myTest\shiro-tutorial。

在shiro-tutorial目錄下創建pom.xml文件,此maven的xml文件內容如下:

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">

4.0.0

org.apache.shiro.tutorials

shiro-tutorial

1.0.0-SNAPSHOT

First Apache Shiro Application

jar

UTF-8

org.apache.maven.plugins

maven-compiler-plugin

2.0.2

1.5

1.5

${project.build.sourceEncoding}

org.codehaus.mojo

exec-maven-plugin

1.1

java

test

Tutorial

org.apache.shiro

shiro-core

1.1.0

org.slf4j

slf4j-simple

1.6.1

test

3- 構建類

我們將運行一個簡單的命令行應用程序,因此我們需要創建一個Java類,其擁有公開靜態方法void main(String args)方法。

在包含pom.xml文件的同一目錄中(上文創建的目錄),創建一個* src/main/java子目錄。 在src/main/java中創建一個包含以下內容的Tutorial.java文件:

import org.apache.shiro.SecurityUtils;

import org.apache.shiro.authc.*;

import org.apache.shiro.config.IniSecurityManagerFactory;

import org.apache.shiro.mgt.SecurityManager;

import org.apache.shiro.session.Session;

import org.apache.shiro.subject.Subject;

import org.apache.shiro.util.Factory;

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

public class Tutorial {

private static final transient Logger log = LoggerFactory.getLogger(Tutorial.class);

public static void main(String[] args) {

log.info("My First Apache Shiro Application");

System.exit(0);

}

}

Apache Shiro 安全框架入門系列—4-親手打造第一個Shiro應用

上源代碼截圖

現在不要擔心import語句問題,我們很快就會理解它們。 但現在,我們已經有了一個典型的命令行'shell'程序。 這些程序要做的就是打印出"My First Apache Shiro Application"並退出。

4- 測試運行

為測試我們的教程應用程序,請在命令行模式下,進入到教程項目的根目錄(例如shiro-tutorial)下,在命令提示符中執行以下命令:mvn compile exec:java

你會看到我們的小教程"應用程序"運行並退出。 您應該看到類似以下內容(紅線部分文本,為程序的輸出):

Apache Shiro 安全框架入門系列—4-親手打造第一個Shiro應用

注意,在執行上述命令時,mvn會執行一下必要的初始化工作,如下載相關組建包等,下次再運行時,就不會再下載了

我們已驗證應用程序成功運行 - 現在讓我們啟用Apache Shiro。

繼續本教程時,您可以在每次添加更多代碼後運行mvn compile exec:java,以查看更改後運行結果。

4.2、啟用Shio

在應用程序中啟用Shiro首先要了解的是,Shiro中的幾乎所有內容都與稱為SecurityManager的中央/核心組件有關。 對於那些熟悉Java安全性的人來說,這是Shiro的SecurityManager概念 - 它與java.lang.SecurityManager不同。

雖然我們在體系結構章節中詳細介紹Shiro的設計,但現在知道Shiro SecurityManager是應用程序的Shiro環境核心,並且每個應用程序必須存在一個SecurityManager,這就足夠好了。 因此,我們必須在我們的教程應用程序中做的第一件事是設置SecurityManager實例。

1- 配置

雖然我們可以直接實例化SecurityManager類,但Shiro的SecurityManager實現具有足夠的配置選項和內部組件,這使得在Java源代碼中很難做到這一點 ,因此使用靈活的基於文本格式文件來配置SecurityManager會容易得多。

為此,Shiro通過基於文本的INI配置提供默認的"公分母"解決方案。 現在人們對使用龐大的XML文件感到厭倦,INI易於閱讀、使用簡單,並且只需很少的依賴關係。 稍後您將會看到,通過對對象圖導航的簡單瞭解,INI可以有效地用於配置像SecurityManager這樣的簡單對象圖。

注意:SecurityManager有很多配置項。

Shiro的SecurityManager實現和所有支持組件都與JavaBean兼容。 這使得Shiro可以使用幾乎任意配置格式進行配置,如XML(Spring,JBoss,Guice等),YAML,JSON,Groovy Builder標記等等。 INI只是Shiro的'公分母'格式,允許在任何環境下進行配置,以防其他選項無法使用。

2- shiro.ini

我們使用INI文件來為這個簡單的應用程序配置Shiro安全管理器SecurityManager。 首先,從pom.xml所在的同一目錄下創建一個src/main/resources目錄。 然後在該新目錄中使用以下內容創建一個shiro.ini文件(配置清單src/main/resources/shiro.ini):

# =============================================================================

# Tutorial INI configuration

#

# Usernames/passwords are based on the classic Mel Brooks' film "Spaceballs" :)

# =============================================================================

# -----------------------------------------------------------------------------

# Users and their (optional) assigned roles

# username = password, role1, role2, ..., roleN

# -----------------------------------------------------------------------------

[users]

root = secret, admin

guest = guest, guest

presidentskroob = 12345, president

darkhelmet = ludicrousspeed, darklord, schwartz

lonestarr = vespa, goodguy, schwartz

# -----------------------------------------------------------------------------

# Roles with assigned permissions

# roleName = perm1, perm2, ..., permN

# -----------------------------------------------------------------------------

[roles]

admin = *

schwartz = lightsaber:*

goodguy = winnebago:drive:eagle5

正如你所看到的,這個配置基本上建立了一小組靜態用戶帳戶,對於我們第一個應用程序已經足夠好了。 在後面的章節中,您將看到我們如何使用更復雜的用戶數據源,如關係數據庫,LDAP和ActiveDirectory等等。

3- 引用配置

現在我們已經定義了一個INI文件,可以在我們的教程應用程序類中創建SecurityManager實例。

更改main方法如下:

public static void main(String[] args) {

log.info("My First Apache Shiro Application");

//1.

Factory factory = new IniSecurityManagerFactory("classpath:shiro.ini");

//2.

SecurityManager securityManager = factory.getInstance();

//3.

SecurityUtils.setSecurityManager(securityManager);

System.exit(0);

}

Apache Shiro 安全框架入門系列—4-親手打造第一個Shiro應用

源代碼截圖

我們在初始代碼中添加了3行代碼後,Shiro在示例應用程序中啟用! 這是多容易是吧?

隨意運行mvn compile exec:java,並看到所有東西仍然能夠成功運行(由於Shiro默認的調試日誌記錄或更低日誌等級,所以你不會看到任何Shiro日誌消息 - 如果它啟動並且沒有錯誤地運行,那麼你就瞭解到一切都是正常的)。

這是上述補充內容的描述:

1.我們使用Shiro的IniSecurityManagerFactory實現來獲取位於classpath根目錄下的shiro.ini文件。 這種實現反映了Shiro對工廠方法設計模式的支持。 classpath:前綴是一個資源指示符,告訴shiro從哪裡加載ini文件(其他前綴,如url:和file:也受支持)。

2.調用factory.getInstance()方法,該方法解析INI文件並返回反映配置的SecurityManager實例。

3.在這個簡單的例子中,我們將SecurityManager設置為一個可以通過JVM訪問的靜態(內存)單例。 但是請注意,如果您將在單個JVM中擁有多個支持Shiro的應用程序,那麼這是不可取的。 對於這個簡單的例子,這是可以的,但更復雜的應用程序環境通常會將SecurityManager放置在特定於應用程序的內存中(例如在Web應用程序的ServletContext或Spring,Guice或JBoss DI容器實例中)

4.3、使用Shiro

我們的SecurityManager已經準備就緒,現在可以開始做我們真正關心的事情 - 執行安全操作。

在確保我們的應用程序安全時,我們自問最相關的問題可能是"誰是當前用戶?"或"當前用戶是否允許執行X?"? 在我們編寫代碼或設計用戶接口時,常常會提出這些問題:應用程序通常基於用戶故事而構建,並且您希望基於每個用戶來展現(和保護)功能。 因此,我們在應用程序中考慮安全性的最自然方式是基於當前用戶。 Shiro的API從根本上代表了"目前用戶"主張與其主體概念。

幾乎在所有環境中,您都可以通過以下調用獲取當前正在執行的用戶:

Subject currentUser = SecurityUtils.getSubject();

使用SecurityUtils.getSubject(),我們可以獲得當前正在執行的Subject。 主體是一個安全術語,基本上意味著"當前正在執行的用戶的特定安全視圖"。 它不被稱為"用戶",因為"用戶"一詞通常與人類相關聯。 在安全領域,"主體"這個術語可能意味著一個人,也可能是一個第三方進程、cron作業、守護進程帳戶或任何類似的東西。 它只是意味著"當前與軟件交互的東西"。 不過,對於大多數意圖和目的,您可以將主體視為Shiro的"用戶"概念。

獨立應用程序中的getSubject()調用,其可能會根據特定於應用程序的位置中的用戶數據以及服務器環境(例如Web應用程序)返回Subject,並根據與當前線程或傳入請求關聯的用戶數據獲取Subject 。

現在你有一個主體,你可以用它做什麼?

如果您想在應用程序的當前會話期間向用戶提供可用的內容,則可以獲得他們的會話:

Session session = currentUser.getSession();

session.setAttribute( "someKey", "aValue" );

此Session是一個Shiro特定的實例,它提供了大多數你習慣的常規HttpSession的實例,但有一些額外的好處和一個很大的區別:它不需要HTTP環境!

如果在Web應用程序內部署,默認情況下會話將基於HttpSession。 但是,在非Web環境中,像這個簡單的教程應用程序,Shiro默認會自動使用其企業會話管理。 這意味著無論部署環境如何,您都可以在任何層中的應用程序中使用相同的API! 這將打開一個全新的應用程序世界,因為任何需要會話的應用程序都不需要強制使用HttpSession或EJB Stateful Session Beans。 而且,任何客戶端技術現在都可以共享會話數據。

所以現在你可以獲得一個Subject主體和Session會話。 但那些真正有用的,如檢查是否允許他們做事、檢查角色和權限等是關於什麼的?

其實,我們只能對已知的用戶進行這些檢查。 上面的Subject實例代表當前用戶,但是誰是當前用戶? 那麼,他們是匿名的——也就是說,直到他們至少登錄一次。 所以,讓我們來這樣做:

if ( !currentUser.isAuthenticated() ) {

//以gui特定方式收集用戶主體和憑證-principals and credentials

//如html表單的用戶名/密碼,X509證書,OpenID等。

//我們將在這裡使用用戶名/密碼示例,因為它是最常見的。

//(你知道這是什麼電影嗎?;)

UsernamePasswordToken token = new UsernamePasswordToken("lonestarr", "vespa");

//這就是你需要做的所有事情以便來支持'記住我'(沒有配置 - 內置!)

token.setRememberMe(true);

currentUser.login(token);

}

Apache Shiro 安全框架入門系列—4-親手打造第一個Shiro應用

就這麼簡單!

但是,如果他們的登錄嘗試失敗呢? 你可以捕捉各種具體的例外情況,告訴你到底發生了什麼,並允許你相應地處理和做出反應:

try {

currentUser.login( token );

//如果沒有例外,就是這樣,搞定!

} catch ( UnknownAccountException uae ) {

//用戶名不在系統中,如何向他們顯示錯誤消息?

} catch ( IncorrectCredentialsException ice ) {

//密碼不匹配,是否再試?

} catch ( LockedAccountException lae ) {

//該用戶名的帳戶被鎖定 - 無法登錄。如何顯示一條消息?

}

... 更多類型的異常檢查——如果你想要 ...

} catch ( AuthenticationException ae ) {

//意外情況 - 怎麼處理?

}

Apache Shiro 安全框架入門系列—4-親手打造第一個Shiro應用

源代碼截圖

您可以檢查許多不同類型的例外情況,或者根據Shiro可能無法解釋的自定義條件拋出自己的例外情況。 有關更多信息,請參閱AuthenticationException JavaDoc(http://shiro.apache.org/static/current/apidocs/org/apache/shiro/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." );

}

還可以看到他們是否有權對某種類型的實體採取行動:

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.

4.4、最終Tutorial類

Apache Shiro 安全框架入門系列—4-親手打造第一個Shiro應用

4.5、示例小結

希望這篇入門教程能幫助您瞭解如何在基本應用程序中設置Shiro以及Shiro的主要設計概念Subject和SecurityManager。

但這是一個相當簡單的應用程序。 您可能會問自己,"如果我不想使用INI用戶帳戶,而想連接到更復雜的用戶數據源,該怎麼辦?"

要回答這個問題,需要對Shiro的體系結構和配置支持機制有更深入的瞭解。

下一篇崔老師將介紹Shiro的詳細架構。敬請期待吧~^_^

注意:各位學友,這個系列的文章,一定要從頭認真看,理解基本操作和核心概念及步驟。

相信您一定可以輕鬆掌握Shiro這個Java安全框架。

Apache Shiro 安全框架入門系列—4-親手打造第一個Shiro應用


分享到:


相關文章: