1. 程式人生 > >Shiro官方文件之第一個Shiro程式

Shiro官方文件之第一個Shiro程式

Your First Apache Shiro Application

If you’re new to Apache Shiro, this short tutorial will show you how to set up an initial and very simple application secured by Apache Shiro. We’ll discuss Shiro’s core concepts along the way to help familiarize you with Shiro’s design and API.

如果你是剛開始使用Apache Shiro, 這個簡短的教程會教你怎麼使用Apache Shiro去建立一個初始的簡單的安全應用程式。我們會討論Shiro的核心概念來幫助你熟悉Shiro的設計和API。

If you don’t want to actually edit files as you follow this tutorial, you can obtain a nearly identical sample application and reference it as you go. Choose a location:

如果你不想在學習這個教程時實際編輯檔案,你可以獲取一個幾乎相同的例子程式來引用。 選擇一個地址:<br/ >

In Apache Shiro’s source distribution’s samples/quickstart directory. The source distribution is available from the Download page.

在Apache Shiro原始碼發行版的samples/quickstart目錄中。原始碼釋出可以從下載頁面獲得。

Setup 設定

In this simple example, we’ll create a very simple command-line application that will run and quickly exit, just so you can get a feel for Shiro’s API.

這個簡單的例子程式,我們會建立一個簡單的命令列應用程式來來執行和退出,你可以對Shiro的API有一些瞭解。

Any Application Apache Shiro was designed from day one to support any application - from the smallest command-line applications to the largest clustered web applications. Even though we’re creating a simple app for this tutorial, know that the same usage patterns apply no matter how your application is created or where it is deployed.

Apache Shiro 一個始就被設計為支援任何應用程式——從小的命令列應用程式到大型叢集web應用程式。儘管這個教程我們建立一個簡單的app,但是要知道,相同的使用模式的不管你的應用程式如何建立或者怎麼部署都適用。

This tutorial requires Java 1.5 or later. We’ll also be using Apache Maven as our build tool, but of course this is not required to use Apache Shiro. You may acquire Shiro’s .jars and incorporate them in any way you like into your application, for example maybe using Apache Ant and Ivy.

這個教程要求Java1.5或者更高。我們同樣使用Apache Maven作為我們的構建工具,當然這不是使用Apache Shiro必須的。你可以獲取Shiro.jar並以任何你喜歡的方式包含到你的應用程式中,例如Apache Ant 和 Ivy。

For this tutorial, please ensure that you are using Maven 2.2.1 or later. You should be able to type mvn --version in a command prompt and see something similar to the following:

根據這個教程,請保證你使用的是Maven 2.2.1或者更高。你應該在鍵入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”

For now, create a new directory on your filesystem, for example, shiro-tutorial and save the following Maven pom.xml file in that directory:

從現在開始,建立換一個新的資料夾在你的檔案系統,例如,shiro-tutorial並且儲存下列的Maven pom.xml 檔案在這個資料夾中:

pom.xml

<?xml version="1.0" encoding="UTF-8"?>
    <project xmlns="http://maven.apache.org/POM/4.0.0"
        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">

    <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.slf4j.org for more info. -->
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-simple</artifactId>
            <version>1.6.1</version>
            <scope>test</scope>
        </dependency>
    </dependencies>

</project>

The Tutorial class We’ll be running a simple command-line application, so we’ll need to create a Java class with a public static void main(String[] args) method.

這個教程會執行一個簡單的命令列程式,所以我們需要建立一個帶有 public static void main(String[] args) 方法的Java類。

In the same directory containing your pom.xml file, create a *src/main/java sub directory. In src/main/java create a Tutorial.java file with the following contents:

在包含你的pom.xml檔案的相同目錄下,建立src/main/java資料夾。在src/main/java目錄下新建一個包含一下內容的Tutorial.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);
    }
}

Don’t worry about the import statements for now - we’ll get to them shortly. But for now, we’ve got a typical command line program ‘shell’. All this program will do is print out the text “My First Apache Shiro Application” and exit.

現在不要擔心這些匯入語句 —— 我們很快就會講到。但是現在,我們要有一個典型的命令列’shell’程式。這個程式會列印"My First Apache Shiro Application"並且退出。

Test Run

To try our Tutorial application, execute the following in a command prompt in your tutorial project’s root dirctory (e.g. shiro-tutorial), and type the following:

在你教程工程的根目錄執行下列命令提示去嘗試執行Tutorial程式:

mvn compile exec:java

And you will see our little Tutorial ‘application’ run and exit. You should see something similar to the following (notice the bold text, indicating our output):

你會看到我們這個小程式執行然後退出。你應該會看到一些類似下列資訊的東西(注意粗體文字,表示我們的輸出):

Run the Application

執行這個程式:

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

… a bunch of Maven output …

Maven 輸出:


1 [Tutorial.main()] INFO Tutorial - My First Apache Shiro Application
lhazlewood:~/projects/shiro-tutorial\$

We’ve verified the application runs successfully - now let’s enable Apache Shiro. As we continue with the tutorial, you can run mvn compile exec:java after each time we add some more code to see the results of our changes.

我們已經核實了程式已經成功的執行 —— 現在讓讓我們開始Apache Shiro。繼續這個教程,你可以在我們每次新增一些程式碼想看到一個改變結果時執行mvn compile exec:java

Enable Shiro

The first thing to understand in enabling Shiro in an application is that almost everything in Shiro is related to a central/core component called the SecurityManager. For those familiar with Java security, this is Shiro’s notion of a SecurityManager - it is NOT the same thing as the java.lang.SecurityManager.

在一個應用程式中開啟Shiro的第一件要了解的事就是與幾乎所有事都相關的核心元件SecurityManager。對於那些熟悉Java安全shur的人來說,這個SecurityManager是Shiro的概念——並不是相同的java.lang.SecurityManager。

While we will cover Shiro’s design in detail in the Architecture chapter, it is good enough for now to know that the Shiro SecurityManager is the core of a Shiro environment for an application and one SecurityManager must exist per application. So, the first thing we must do in our Tutorial application is set-up the SecurityManager instance.

我們會在架構章節討論有關Shiro的詳細設計。現在知道Shiro SecurityManager是一個應用裡Shiro環境的核心,並且每一個應用都應該有一個SecurityManager就足夠了。所以我們在這個教程中必須要做的第一件事是建立一個SecurityManager的例項。

Configuration

While we could instantiate a SecurityManager class directly, Shiro’s SecurityManager implementations have enough configuration options and internal components that make this a pain to do in Java source code - it would be much easier to configure the SecurityManager with a flexible text-based configuration format.

我們可以馬上例項化一個SecurityManager類,Shiro的SecurityManger實現有許多配置 選項和內部元件,這在java原始碼中做到這一個是很痛苦的(很難)—— 使用靈活的文字配置格式會使用SecurityManager的配置變得非常簡單。

To that end, Shiro provides a default ‘common denominator’ solution via text-based INI configuration. People are pretty tired of using bulky XML files these days, and INI is easy to read, simple to use, and requires very few dependencies. You’ll also see later that with a simple understanding of object graph navigation, INI can be used effectively to configure simple object graphs like the SecurityManager.

最後,Shiro提供了一個預設的’公分母’(就是那個.ini檔案)解決方案經由文字INI配置.人們對使用笨重xml檔案已經非常疲憊了,而INI檔案容易閱讀,使用簡單,只需要非常少的依賴。稍後你會看到對物件導圖的簡單理解,INI可以有效的配置物件圖比如SecurityManager。

Many Configuration Options

Shiro’s SecurityManager implementations and all supporting components are all JavaBeans compatible. This allows Shiro to be configured with practically any configuration format such as XML (Spring, JBoss, Guice, etc), YAML, JSON, Groovy Builder markup, and more. INI is just Shiro’s ‘common denominator’ format that allows configuration in any environment in case other options are not available.

Shiro的SecurityManager實現和支援所有的JavaBean相容。這允許Shiro可以被任意的配置格式,比如xml,YAML,JSON,Groovy Builder標記等。INI就Shiro的’公分母’格式,它允許在任何環境中配置一防其他情況(其他配置檔案)不可用。

shiro.ini

So we’ll use an INI file to configure the Shiro SecurityManager for this simple application. First, create a src/main/resources directory starting in the same directory where the pom.xml is. Then create a shiro.ini file in that new directory with the following contents:

所以這個簡單的應用程式我們使用INI檔案去配置Shiro SecurityManager。首先,在pom.xml開始的相同的資料夾新建一個 src/mai/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

As you see, this configuration basically sets up a small set of static user accounts, good enough for our first application. In later chapters, you will see how we can use more complex User data sources like relational databases, LDAP an ActiveDirectory, and more.

你看到了嗎,這個配置主要建立了一組小的靜態使用者賬戶,足夠滿足於我們的第一個應用程式。在後續的章節,你會看到我們如何更復雜的使用User資料來源就像關係型資料庫、LDAP等等。

Referencing the Configuration

Now that we have an INI file defined, we can create the SecurityManager instance in our Tutorial application class. Change the main method to reflect the following updates:

現在我們有一個已經定義好的INI檔案了,我們可以在應用程式中建立SecurityManager例項了。如下方式改變main方法:

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);

} And there we go - Shiro is enabled in our sample application after adding only 3 lines of code! How easy was that?

我們繼續 —— 在這個簡單的應用在我們添加了3行程式碼後就Shiro已經開啟了。是不是很簡單?

Feel free to run mvn compile exec:java and see that everything still runs successfully (due to Shiro’s default logging of debug or lower, you won’t see any Shiro log messages - if it starts and runs without error, then you know everything is still ok).

隨變執行 mvn compile exec:java這個命令,你會看到依然成功執行(由於Shiro預設的debug或更低的日誌級別,你不會看到shiro日誌資訊——如果它啟動執行沒有錯誤,所有的依然是可以的。)

Here is what the above additions are doing:

這裡是上面新增的內容:

We use Shiro’s IniSecurityManagerFactory implementation to ingest our shiro.ini file which is located at the root of the classpath. This implementation reflects Shiro’s support of the Factory Method Design Pattern. The classpath: prefix is an resource indicator that tells shiro where to load the ini file from (other prefixes, like url: and file: are supported as well).

我們使用Shiro的IniSecurityManager實現來讀取在類路徑根目錄下的shiro.ini檔案。這個實現反應了Shiro的工廠方法設計模式的支援。這個classpath:字首是一個資源指示器,用來告訴shiro去哪裡載入這個ini配置檔案(其他的字首,像url: 和 file: 也同樣被支援)。

The factory.getInstance() method is called, which parses the INI file and returns a SecurityManager instance reflecting the configuration.

這個factory.getInstance()方法被呼叫,它解析了這個INI檔案並且返回了一個反映這個配置的SecurityManager例項

In this simple example, we set the SecurityManager to be a static (memory) singleton, accessible across the JVM. Note however that this is not desireable if you will ever have more than one Shiro-enabled application in a single JVM. For this simple example, it is ok, but more sophisticated application environments will usually place the SecurityManager in application-specific memory (such as in a web app’s ServletContext or a Spring, Guice or JBoss DI container instance).

在這個簡單的例子中,我們設定了一個靜態(記憶體)的單例的SecurityManager跨JVM訪問。但是請注意你在單個JVM中有多個應用開啟了Shiro這是不可取的。這個簡單的例子中這樣是可以的,但是複雜的用用環境中通常會把SecurityManager放到應用特殊的記憶體(例如web應用的ServletContext或者一個Spring,guice或者JBoss DI容器例項中)

Using Shiro

Now that our SecurityManager is set-up and ready-to go, now we can start doing the things we really care about - performing security operations.

現在我們的SecurityManager已經準備好了,現在我們可以開始我們真正關心的事了——執行安全操作。,

When securing our applications, probably the most relevant questions we ask ourselves are “Who is the current user?” or “Is the current user allowed to do X”? It is common to ask these questions as we’re writing code or designing user interfaces: applications are usually built based on user stories, and you want functionality represented (and secured) based on a per-user basis. So, the most natural way for us to think about security in our application is based on the current user. Shiro’s API fundamentally represents the notion of ‘the current user’ with its Subject concept.

當保護我們的應用程式時,我們可能問的最多的相關問題是『誰是當前使用者』或者『當前使用者被允許做X嗎?』?當我們在編寫程式碼或者設計使用者介面時最常問到的問題:應用程式通常構建在使用者故事上,你需要基於每個使用者的基礎來表示(和保護)功能。所以我們自然會想到我們應用你程式的安全是基於當前使用者。Shiro API從根本上代表了"當前使用者"概念和Subject概念。

In almost all environments, you can obtain the currently executing user via the following call:

在幾乎所有的環境中,你可以通過下面呼叫獲得當前正在執行的使用者:

Subject currentUser = SecurityUtils.getSubject();

Using SecurityUtils.getSubject(), we can obtain the currently executing Subject. Subject is a security term that basically means “a security-specific view of the currently executing user”. It is not called a ‘User’ because the word ‘User’ is usually associated with a human being. In the security world, the term ‘Subject’ can mean a human being, but also a 3rd party process, cron job, daemon account, or anything similar. It simply means ‘the thing that is currently with the software’. For most intents and purposes though, you can think of the Subject as Shiro’s ‘User’ concept.

使用SecurityUtils.getSubject(),我們可以獲得正在執行的Subject。Subject是一個安全術語,基本意思是當前正在執行的使用者的安全檢視。它不叫做「User」,因為「User」通過是與人類聯絡的。在安全裡面,Subject這個術語可以代表人類,也可以是第三方程式,計劃任務,守護程序,或者任何相似的東西。簡單來說就是當前軟體中的東西。在大多數情況下你可以把Subject看做是Shiro的「User」的概念。

The getSubject() call in a standalone application might return a Subject based on user data in an application-specific location, and in a server environment (e.g. web app), it acquires the Subject based on user data associated with current thread or incoming request.

在一個獨立應用中getSubject()方法的呼叫返回一個基於應用測序特定位置的使用者資料的Subject。在一個伺服器環境中(例如 web app),獲取的Subject是基於與使用者資料相關聯的當前執行緒或者即將到來的請求。

Now that you have a Subject, what can you do with it?

現在你有一個Subject了,你可以用他做什麼呢?

If you want to make things available to the user during their current session with the application, you can get their session:

在應用程式中,你想在這這個使用者會話期間做一些可以做的事,你可以獲取它的session:

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

The Session is a Shiro-specific instance that provides most of what you’re used to with regular HttpSessions but with some extra goodies and one big difference: it does not require an HTTP environment!

這個Session是Shiro特有的例項,它用來提供你熟悉的HttpSession但是提供了額外的好處和一個大的不同:它不需要Http環境。

If deploying inside a web application, by default the Session will be HttpSession based. But, in a non-web environment, like this simple tutorial application, Shiro will automatically use its Enterprise Session Management by default. This means you get to use the same API in your applications, in any tier, regardless of deployment environment! This opens a whole new world of applications since any application requiring sessions does not need to be forced to use the HttpSession or EJB Stateful Session Beans. And, any client technology can now share session data.

如果部署在一個web應用程式裡面,這個Session是基於HttpSession的。但是在一個不是web的應用的程式裡,就像這個教程,Shiro會自動預設使用Enterprise Session Manager。這意味著可以不管在部署環境的那一層你都可以使用相同的API。它開啟了一個應用程式全新的世界,因為任何應用程式都不需要強制使用HttpSession或者EJB有狀態會話bean。現在任何客戶端技術可以分享session資料。

So now you can acquire a Subject and their Session. What about the really useful stuff like checking if they are allowed to do things, like checking against roles and permissions?

現在你可以獲取一個Subject和他的Session了。那麼什麼才是像檢查他們是否被允許去做某件事、像違反某個角色或許可權一樣真正有用的東西?

Well, we can only do those checks for a known user. Our Subject instance above represents the current user, but who is the current user? Well, they’re anonymous - that is, until they log in at least once. So, let’s do that:

當然我們做只能是對一個已知的使用者做這些檢查,我們上面的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.
    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);
}

That’s it! It couldn’t be easier.

就是這樣,這不能在簡單了。

But what if their login attempt fails? You can catch all sorts of specific exceptions that tell you exactly what happened and allows you to handle and react accordingly:

但是他們檢視登入失敗了呢?你可以獲取所有特定的異常,這些異常會告訴你發生了什麼,允許你做相應的處理和反應:


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

There are many different types of exceptions you can check, or throw your own for custom conditions Shiro might not account for. See the AuthenticationException JavaDoc for more.

這裡有許多不同型別的異常你可以用來檢測,或者丟擲你自定義的異常,但是shiro可能不能處理。可以從AuthenticationException文件獲得更多。

Handy Hint

Security best practice is to give generic login failure messages to users because you do not want to aid an attacker trying to break into your system.

安全的最佳實踐是返回登入失敗訊息,應為你不會想要幫助一個檢視破壞你係統的攻擊者。

Ok, so by now, we have a logged in user. What else can we do?

現在我們有了一個登入的使用者,我們能做什麼呢?

Let’s say who they are:

讓我們說出他是誰:

//print their identifying principal (in this case, a username): 
log.info( "User [" + currentUser.getPrincipal() + "] logged in successfully." );
We can also test to see if they have specific role or not:

if ( currentUser.hasRole( "schwartz" ) ) {
    log.info("May the Schwartz be with you!" );
} else {
    log.info( "Hello, mere mortal." );
}

We can also see if they have a permission to act on a certain type of entity:

我們也可以看一下他們是否有許可權對某個實體採取行動:

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

Also, we can perform an extremely powerful instance-level permission check - the ability to see if the user has the ability to access a specific instance of a type:

另外我們還可以執行一個非常強大的例項檢查——檢視使用者是否能夠特定型別的例項:

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

Piece of cake, right?

Finally, when the user is done using the application, they can log out:

最後,當用戶結束使用這個系統,他們可以退出:

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

Final Tutorial class

After adding in the above code examples, here is our final Tutorial class file. Feel free to edit and play with it and change the security checks (and the INI configuration) as you like:

當新增完上面的例子程式碼,這裡是我們最終的教程類的檔案。您可以隨意編輯和使用它,並根據需要更改安全檢查(和INI配置):

Final 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");

        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() + "