日韩黑丝制服一区视频播放|日韩欧美人妻丝袜视频在线观看|九九影院一级蜜桃|亚洲中文在线导航|青草草视频在线观看|婷婷五月色伊人网站|日本一区二区在线|国产AV一二三四区毛片|正在播放久草视频|亚洲色图精品一区

分享

Apache Shiro 示例

 且看且珍惜 2014-09-23

第一個Apache Shiro程序

 

如果你是初次接觸Apache Shiro,該文章將指導(dǎo)你創(chuàng)建一個初級的非常簡單的使用Apache Shiro進行安全認證的程序,同時我們將討論Shiro的核心理念以幫助你熟悉Shiro的設(shè)計方式和API。

 

如果你確實不想按照該示例一步一步地編寫代碼,你可以從下面地址下載一個基本上完全相同的程序作為參考,選擇下載位置:

    Apache Shiro的版本庫中: https://svn./repos/asf/shiro/trunk/samples/quickstart/

    Apache Shiro的源碼發(fā)布的samples/quickstart目錄中,源碼發(fā)布在 Downloadhttp://shiro./download.html)頁面。

 

Setup

在這個簡單示例中,我們將建立一個非常簡單的命令行程序,你可以從中感受一下ShiroAPI。

注意:任何程序

Apache Shrio從設(shè)計之初就是為了支持所有程序--從最小的命令行程序到大型的集群的web程序,雖然我們在這個向?qū)е兄皇褂昧艘粋€簡單的程序,但要知道無論你的程序如何創(chuàng)建發(fā)布到何處,這種方式都適用。

 

該示例需要Java1.5及更高版本,同時用Apache Maven作為建造工具,但這不是Apache Shiro所必須的。你可以獲得Shirojar并以你喜歡的任何方式將其加入你的程序中,例如你可以使用antivy。

在該示例中,請確定你使用的是Maven2.2.1或更高版本,你可以在命令窗口中執(zhí)行“mvn --version”看到和下面類似的輸出:

 

Testing Maven Installation

hazlewood:~/shiro-tutorial$ mvn --version

Apache Maven 2.2.1 (r801777; 2009-08-06 12:16:01-0700)

Java version: 1.6.0_24

Java home: /System/Library/Java/JavaVirtualMachines/1.6.0.jdk/Contents/Home

Default locale: en_US, platform encoding: MacRoman

OS name: "mac os x" version: "10.6.7" arch: "x86_64" Family: "mac"

 

現(xiàn)在,創(chuàng)建一個新的目錄,例如shiro-tutorial 并將下面的Mavenpom.xml文件保存在同一目錄下:

pom.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven./POM/4.0.0"
        xmlns:xsi="http://www./2001/XMLSchema-instance"
        xsi:schemaLocation="http://maven./POM/4.0.0 http://maven./maven-v4_0_0.xsd">
  
   <modelVersion>4.0.0</modelVersion>
   <groupId>org.apache.shiro.tutorials</groupId>
   <artifactId>shiro-tutorial</artifactId>
   <version>1.0.0-SNAPSHOT</version>
   <name>First Apache Shiro Application</name>
   <packaging>jar</packaging>
  
   <properties>
       <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
   </properties>
  
   <build>
       <plugins>
           <plugin>
               <groupId>org.apache.maven.plugins</groupId>
               <artifactId>maven-compiler-plugin</artifactId>
               <version>2.0.2</version>
               <configuration>
                   <source>1.5</source>
                   <target>1.5</target>
                   <encoding>${project.build.sourceEncoding}</encoding>
               </configuration>
           </plugin>
  
           <!-- This plugin is only to test run our little application.  It is not
                needed in most Shiro-enabled applications: -->
           <plugin>
               <groupId>org.codehaus.mojo</groupId>
               <artifactId>exec-maven-plugin</artifactId>
               <version>1.1</version>
               <executions>
                   <execution>
                       <goals>
                           <goal>java</goal>
                       </goals>
                   </execution>
               </executions>
               <configuration>
                   <classpathScope>test</classpathScope>
                   <mainClass>Tutorial</mainClass>
               </configuration>
           </plugin>
       </plugins>
   </build>
  
   <dependencies>
       <dependency>
           <groupId>org.apache.shiro</groupId>
           <artifactId>shiro-core</artifactId>
           <version>1.1.0</version>
       </dependency>
       <!-- Shiro uses SLF4J for logging.  We'll use the 'simple' binding
            in this example app.  See http://www. for more info. -->
       <dependency>
           <groupId>org.slf4j</groupId>
           <artifactId>slf4j-simple</artifactId>
           <version>1.6.1</version>
     z      <scope>test</scope>
       </dependency>
   </dependencies>
  
</project>

 

示例類文件

我們準(zhǔn)備運行的是一個命令行程序,所以我們需要創(chuàng)建一個帶有public static void main(String[] args)函數(shù)的Java類。

pom.xml同目錄里,創(chuàng)建一個src/main/java子目錄,在該子目錄里創(chuàng)建一個Tutorial.java文件,內(nèi)容如下:

src/main/java/Tutorial.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
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);
   }
}

 

先不要考慮里面的import,我們馬上就會獲取它們,現(xiàn)在,我們已經(jīng)有了一個典型的命令行程序'shell',這個程序所做的事情就是輸出文字“My First Apache Shiro Application”然后退出。

 

運行

在你的該示例項目根目錄里(例如shiro-tutorial)執(zhí)行下面的命令行來運行程序:

mvn compile exec:java

你可以看到我們的這個小程序運行并且退出,你將看到類似于下面這樣的輸出住處(注意加粗字體,標(biāo)示著我們的輸出)

Run the Application

lhazlewood:~/projects/shiro-tutorial$ mvn compile exec:java

 

... a bunch of Maven output ...

 

1 [Tutorial.main()] INFO Tutorial - My First Apache Shiro Application

lhazlewood:~/projects/shiro-tutorial\$

 

我們驗證程序已經(jīng)成功運行--現(xiàn)在,讓我們加上Apache Shiro,今后,你可以在我們加上任何代碼之后運行mvn compile exec:java命令查看我們更改的結(jié)果。

 

使用Shiro

使用shiro要理解的第一件事情是shiro幾乎所有的事情都和一個中心組件SecurityManager有關(guān),對于那些熟悉Java security的人請注意:這和java.lang.SecurityManager不是一回事。

 

我們將在Architecture章節(jié)詳細描述shiro的設(shè)計,但現(xiàn)在有必要知道Shrio SecurityManager是程序中Shiro的核心,每一個程序都必定會存在一個SecurityManager,所以,在我們這個示例程序中必須做的第一件事情是建立一個SecurityManager實例。

 

配置

雖然我們可以直接對SecurityManager實例化,但在Java代碼中對ShiroSecurityManager所須的選項和內(nèi)部組件進行配置會讓人感覺有點小痛苦--而將這些SecurityManager配置用一個靈活的配置文件實現(xiàn)就會簡單地多。

為此,Shiro默認提供了一個基本的INI配置文件的解決方案,人們已經(jīng)對龐大的XML文件有些厭倦了,而一個INI文件易讀易用,而且所依賴的組件很少,稍后你就會通過一個簡單易懂的示例明白INI在對簡單對象進行配置的時候是非常有效率的,比如SecurityManager。

 

多種配置選擇

ShiroSecurityManager的實現(xiàn)和其所依賴的組件都是JavaBean,所以可以用多種形式對Shiro進行配置,比如XMLSpring, JBoss, Guice, 等等),YAML, JSON, Groovy Builder markup,及其它,INI只是Shiro一種最基本的配置方式,使得其可以在任何環(huán)境中進行配置比如在那些沒有以上配置形式的環(huán)境中。

 

shiro.ini

在這個示例中我們使用一個INI文件來配置Shiro SecurityManager,首先,在pom.xml同目錄中創(chuàng)建一個src/main/resources子目錄,在該子目錄中創(chuàng)建一個shiro.ini文件,內(nèi)容如下:

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

 

可以看到,在該配置文件中最基礎(chǔ)地配置了幾個靜態(tài)的帳戶,對我們這一個程序已經(jīng)足夠了,在以后的章節(jié)中,將會看到如何使用更復(fù)雜的用戶數(shù)據(jù)比如數(shù)據(jù)庫、LDAP和活動目錄等。

 

引用配置文件

現(xiàn)在我們已經(jīng)定義了一個INI文件,我們可以在我們的示例程序中創(chuàng)建SecurityManager實例了,將main函數(shù)中的代碼進行如下調(diào)整:

public static void main(String[] args) {

 

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

 

   //1.

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

 

   //2.

   SecurityManager securityManager = factory.getInstance();

 

   //3.

   SecurityUtils.setSecurityManager(securityManager);

 

   System.exit(0);

}

 

這就是我們要做的--僅僅使用三行代碼就把Shiro加進了我們的程序,就是這么簡單。

 

執(zhí)行mvn compile exec:java 可以看到程序成功的運行(由于Shiro默認在debug或更底層才記錄日志,所以你不會看到任何Shiro的日志住處--只要運行時沒有錯誤提示,你就可以知道已經(jīng)成功了)。

 

上面所加入的代碼做了下面的事情:

1. 使用ShiroIniSecurityManagerFactory加載了我們的shiro.ini文件,該文件存在于classpath根目錄里。這個執(zhí)行動作反映出shiro支持Factory Method Design Pattern。classpath:資源的指示前綴,告訴shiro從哪里加載ini文件(其它前綴,如url:file:也被支持)。

2.factory.getInstance()方法被調(diào)用,該方法分析INI文件并根據(jù)配置文件返回一個SecurityManager實例。

3.在這個簡單示例中,我們將SecurityManager設(shè)置成了static (memory) singleton,可以通過JVM訪問,注意如果你在一個JVM中加載多個使用shiro的程序時不要這樣做,在這個簡單示例中,這是可以的,但在其它成熟的應(yīng)用環(huán)境中,通常會將SecurityManager放在程序指定的memory(如在web中的ServletContexct或者Spring、Guice JBoss DI 容器實例)中。

 

使用Shiro

現(xiàn)在我們的SecurityManager已經(jīng)準(zhǔn)備好了,我們可以開始進行我們真正關(guān)心的事情--執(zhí)行安全操作了。

 

為了保護我們的程序安全,我們或許問自己最多的問題就是“誰是當(dāng)前的用戶?”或者“當(dāng)前用戶是否允許做某件事?”通常我們會在寫代碼或者設(shè)計用戶接口的時候問這些問題:程序通常建立在用戶基礎(chǔ)上,程序功能展示(和安全)也基于每一個用戶。所以,通常我們考慮我們程序安全的方法也建立在當(dāng)前用戶的基礎(chǔ)上,ShiroAPI提供了'the current user'概念,即它的Subject。

在幾乎所有的環(huán)境中,你可以通過如下語句得到當(dāng)前用戶的信息:

Subject currentUser = SecurityUtils.getSubject();

 

使用SecurityUtils.getSubject(),我們可以獲取當(dāng)前執(zhí)行的Subject,Subject是一個安全術(shù)語意思是“當(dāng)前運行用戶的指定安全視圖(a security-specific view of the currently executing user)”,這里并不稱之為“User”因為“User”這個詞通常和一個人相關(guān),但在安全認證中,“Subject”可以認為是一個人,也可以認為是第三方進程、時鐘守護任務(wù)、守護進程帳戶或者其它。它可簡單描述為“當(dāng)前和軟件進行交互的事件”,在大多數(shù)情況下,你可以認為它是一個“人(User)”。

 

在一個獨立的程序中調(diào)用getSubject()會在程序指定位置返回一個基于用戶數(shù)據(jù)的Subject,在服務(wù)器環(huán)境(如web程序)中,它將獲取一個和當(dāng)前線程或請求相關(guān)的基于用戶數(shù)據(jù)的Subject

現(xiàn)在你得到了Subject,你可以利用它做什么呢?

如果你針對該用戶希望一些事情在程序當(dāng)前會話期內(nèi)可行,你可以獲取他們的session

Session session = currentUser.getSession();

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

 

Sessionshiro指定的一個實例,提供基本上所有HttpSession的功能,但具備額外的好處和不同:它不需要一個HTTP環(huán)境!

 

如果發(fā)布到一個web程序中,默認情況下Session將會使用HttpSession作為基礎(chǔ),但是,在一個非web程序中,比如該簡單示例程序中,Shiro將自動默認使用它的Enterprise Session Management,這意味著你可以在任何程序中使用相同的API,而根本不需要考慮發(fā)布環(huán)境!這打開了一個全新的世界,從此任何需要session的程序不再需要強制使用HttpSession或者EJB Stateful Session,并且,終端可以共享session數(shù)據(jù)。

 

現(xiàn)在你可以獲取一個Subject和它們的Session,真正填充有用的代碼如檢測其是否被允許做某些事情如何?比如檢查其角色和權(quán)限?

 

我們只能對一個已知用戶做這些檢測,如上我們獲取Subject實例表示當(dāng)前用戶,但是當(dāng)前用戶是認證,嗯,他們是任何人--直到他們至少登錄一次,我們現(xiàn)在就做這件事情:

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.

   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?

}

 

這里有許多不同類別的異常你可以檢測到,也可以拋出你自己異常。

 

小貼士:

最好的方式是將普通的失敗信息反饋給用戶,你總不會希望幫助黑客來攻擊你的系統(tǒng)吧。

 

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

 

讓我們顯示他們是誰:

//print their identifying principal (in this case, a username):

log.info( "User [" + currentUser.getPrincipal() + "] logged in successfully." );

 

我們也可以判斷他們是否擁有某個特定動作或入口的權(quán)限:

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)限檢測,檢測用戶是否具備訪問某個類型特定實例的權(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!");

}

 

非常容易的事,對嗎?

 

最后,當(dāng)用記不再使用系統(tǒng),可以退出登錄:

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

 

最終代碼

在加入上述代碼后,下面的就是我們完整的文件,你可以自由編輯和運行它,可以嘗試改變安全檢測(以及INI配置):

Final src/main/java/Tutorial.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
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");
  
       Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro.ini");
       SecurityManager securityManager = factory.getInstance();
        SecurityUtils.setSecurityManager(securityManager);
  
  
       // get the currently executing user:
       Subject currentUser = SecurityUtils.getSubject();
  
       // Do some stuff with a Session (no need for a web or EJB container!!!)
       Session session = currentUser.getSession();
       session.setAttribute("someKey", "aValue");
       String value = (String) session.getAttribute("someKey");
       if (value.equals("aValue")) {
           log.info("Retrieved the correct value! [" + value + "]");
       }
  
       // let's login the current user so we can check against roles and permissions:
       if (!currentUser.isAuthenticated()) {
           UsernamePasswordToken token = new UsernamePasswordToken("lonestarr", "vespa");
            token.setRememberMe(true);
           try {
               currentUser.login(token);
           } catch (UnknownAccountException uae) {
               log.info("There is no user with username of " + token.getPrincipal());
           } catch (IncorrectCredentialsException ice) {
               log.info("Password for account " + token.getPrincipal() + " was incorrect!");
           } catch (LockedAccountException lae) {
               log.info("The account for username " + token.getPrincipal() + " is locked.  " +
                       "Please contact your administrator to unlock it.");
           }
           // ... catch more exceptions here (maybe custom ones specific to your application?
           catch (AuthenticationException ae) {
               //unexpected condition?  error?
           }
       }
  
       //say who they are:
       //print their identifying principal (in this case, a username):
       log.info("User [" + currentUser.getPrincipal() + "] logged in successfully.");
  
       //test a role:
       if (currentUser.hasRole("schwartz")) {
           log.info("May the Schwartz be with you!");
       } else {
           log.info("Hello, mere mortal.");
       }
  
       //test a typed permission (not instance-level)
       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.");
       }
  
       //a (very powerful) Instance Level permission:
       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!");
       }
  
       //all done - log out!
       currentUser.logout();
  
       System.exit(0);
   }
}

 

總結(jié)

非常希望這示例介紹能幫助你理解如何在基礎(chǔ)程序中加入Shiro,并理解Shiro的設(shè)計理念,SubjectSecurityManager。

但這個程序太簡單了,你可能會問自己,“如果我不想使用INI用戶賬號,而希望連接更為復(fù)雜的用戶數(shù)據(jù)源呢?”

解決這些問題需要更深入地了解shiro的架構(gòu)和配置機制,我們將在下一節(jié)Architecture中介紹。

 

原文地址:http://shiro./tutorial.html

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多