blob: af382625380373c06e31d351bdf50b1304e62ce1 [file] [log] [blame]
<h1><a name="10MinuteTutorial-10MinuteTutorialonApacheShiro"></a>10 Minute Tutorial on Apache Shiro</h1>
<div class="addthis_toolbox addthis_default_style">
<a class="addthis_button_compact" href="http://www.addthis.com/bookmark.php?v=250&amp;pubid=ra-4d66ef016022c3bd">Share</a>
<span class="addthis_separator">|</span>
<a class="addthis_button_preferred_1"></a>
<a class="addthis_button_preferred_2"></a>
<a class="addthis_button_preferred_3"></a>
<a class="addthis_button_preferred_4"></a>
</div>
<script type="text/javascript">var addthis_config = {"data_track_clickback": true};</script>
<script type="text/javascript" src="http://s7.addthis.com/js/250/addthis_widget.js#pubid=ra-4d66ef016022c3bd"></script>
<h2><a name="10MinuteTutorial-Introduction"></a>Introduction</h2>
<p>Welcome to Apache Shiro's 10 Minute Tutoral! </p>
<p>By going through this quick and simple tutorial you should fully understand how a developer uses Shiro in their
application. And you should be able to do it in under 10 minutes.</p>
<h2><a name="10MinuteTutorial-Overview"></a>Overview</h2>
<p>What is Apache Shiro?</p>
<p>Apache Shiro is a powerful and easy to use Java security framework that offers developers an intuitive yet
comprehensive solution to authentication, authorization, cryptography, and session management.</p>
<p>In practical terms, it achieves to manage all facets of your application's security, while keeping out of the way as
much as possible. It is built on sound interface-driven design and OO principles, enabling custom behavior wherever
you can imagine it. But with sensible defaults for everything, it is as "hands off" as application security can be.
At least that's what we strive for.</p>
<p>What can Apache Shiro do?</p>
<p>A lot <img align="middle" class="emoticon" src="https://cwiki.apache.org/confluence/images/icons/emoticons/smile.png"
height="20" width="20" alt="" border="0">. But we don't want to bloat the QuickStart. Please check out our
<a href="features.html" title="Features">Features</a> page if you'd like to see what it can do for you. Also, if
you're curious on how we got started and why we exist, please see the <a href="what-is-shiro.html"
title="What is Shiro">Shiro History and
Mission</a> page.</p>
<p>Ok. Now let's actually do something!</p>
<div class="panelMacro">
<table class="infoMacro">
<colgroup span="1">
<col span="1" width="24">
<col span="1">
</colgroup>
<tr>
<td colspan="1" rowspan="1" valign="top"><img align="middle"
src="https://cwiki.apache.org/confluence/images/icons/emoticons/information.png"
width="16" height="16" alt="" border="0"></td>
<td colspan="1" rowspan="1">Shiro can be run in any environment, from the simplest command line application
to the biggest enterprise web and clustered applications, but we'll use the simplest possible example in
a simple <tt>main</tt> method for this QuickStart so you can get a feel for the API.
</td>
</tr>
</table>
</div>
<h2><a name="10MinuteTutorial-Download"></a>Download</h2>
<ol>
<li>Ensure you have JDK 1.5+ and Maven 2.2+ installed.</li>
<li>Download the lastest "Source Code Distribution" from the <a href="download.html" title="Download">Download</a>
page. In this example, we're using the 1.1.0 release distribution.
</li>
<li>Unzip the source package:
<div class="code panel" style="border-width: 1px;">
<div class="codeContent panelContent">
<pre class="code-java">
&gt; unzip shiro-root-1.2.0-source-release.zip
</pre>
</div>
</div>
</li>
<li>Enter the quickstart directory:
<div class="code panel" style="border-width: 1px;">
<div class="codeContent panelContent">
<pre class="code-java">
&gt; cd shiro-root-1.2.0/samples/quickstart
</pre>
</div>
</div>
</li>
<li>Run the QuickStart:
<div class="code panel" style="border-width: 1px;">
<div class="codeContent panelContent">
<pre class="code-java">
&gt; mvn compile exec:java
</pre>
</div>
</div>
<p>This target will just print out some log messages to let you know what is going on and then exit. While
reading this quickstart, feel free to look at the code found under <tt>samples/quickstart/src/main/java/Quickstart.java</tt>.
Change that file and run the above <tt>mvn compile exec:java</tt> command as often as you like.</p></li>
</ol>
<h2><a name="10MinuteTutorial-Quickstart.java"></a>Quickstart.java</h2>
<p>The <tt>Quickstart.java</tt> file referenced above contains all the code that will get you familiar with the API. Now
lets break it down in chunks here so you can easily understand what is going on.</p>
<p>In almost all environments, you can obtain the currently executing user via the following call:</p>
<p></p>
<div class="code panel" style="border-width: 1px;">
<div class="codeContent panelContent">
<pre class="code-java">
Subject currentUser = SecurityUtils.getSubject();
</pre>
</div>
</div>
<p>Using <tt><a class="external-link"
href="static/current/apidocs/org/apache/shiro/SecurityUtils.html">SecurityUtils</a>.<a
class="external-link" href="static/current/apidocs/org/apache/shiro/SecurityUtils.html#getSubject()">getSubject()</a></tt>,
we can obtain the currently executing <tt><a class="external-link"
href="static/current/apidocs/org/apache/shiro/subject/Subject.html">Subject</a></tt>.
A <em>Subject</em> is just a security-specific "view" of an application User. We actually wanted to call it 'User'
since that "just makes sense", but we decided against it: too many applications have existing APIs that already have
their own User classes/frameworks, and we didn't want to conflict with those. Also, in the security world, the term
<tt>Subject</tt> is actually the recognized nomenclature. Ok, moving on...</p>
<p>The <tt>getSubject()</tt> call in a standalone application might return a <tt>Subject</tt> based on user data in an
application-specific location, and in a server environment (e.g. web app), it acquires the <tt>Subject</tt> based on
user data associated with current thread or incoming request.</p>
<p>Now that you have a <tt>Subject</tt>, what can you do with it?</p>
<p>If you want to make things available to the user during their current session with the application, you can get their
session:</p>
<p></p>
<div class="code panel" style="border-width: 1px;">
<div class="codeContent panelContent">
<pre class="code-java">
Session session = currentUser.getSession();
session.setAttribute( <span class="code-quote">"someKey"</span>, <span class="code-quote">"aValue"</span> );
</pre>
</div>
</div>
<p>The <tt>Session</tt> is a Shiro-specific instance that provides most of what you're used to with regular HttpSessions
but with some extra goodies and one <b>big</b> difference: it does not require an HTTP environment!</p>
<p>If deploying inside a web application, by default the <tt>Session</tt> will be <tt>HttpSession</tt> based. But, in a
non-web environment, like this simple Quickstart, 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 <tt>HttpSession</tt> or EJB Stateful Session Beans. And, any client technology can now share
session data.</p>
<p>So now you can acquire a <tt>Subject</tt> and their <tt>Session</tt>. What about the <em>really</em> useful stuff
like checking if they are allowed to do things, like checking against roles and permissions?</p>
<p>Well, we can only do those checks for a known user. Our <tt>Subject</tt> instance above represents the current user,
but <em>who</em> is the current user? Well, they're anonymous - that is, until they log in at least once. So, let's
do that:</p>
<div class="code panel" style="border-width: 1px;">
<div class="codeContent panelContent">
<pre class="code-java">
<span class="code-keyword">if</span> ( !currentUser.isAuthenticated() ) {
<span class="code-comment">//collect user principals and credentials in a gui specific manner
</span> <span class="code-comment">//such as username/password html form, X509 certificate, OpenID, etc.
</span> <span class="code-comment">//We'll use the username/password example here since it is the most common.
</span> <span class="code-comment">//(<span class="code-keyword">do</span> you know what movie <span
class="code-keyword">this</span> is from? ;)
</span> UsernamePasswordToken token = <span class="code-keyword">new</span> UsernamePasswordToken(<span
class="code-quote">"lonestarr"</span>, <span class="code-quote">"vespa"</span>);
<span class="code-comment">//<span class="code-keyword">this</span> is all you have to <span
class="code-keyword">do</span> to support 'remember me' (no config - built in!):
</span> token.setRememberMe(<span class="code-keyword">true</span>);
currentUser.login(token);
}
</pre>
</div>
</div>
<p>That's it! It couldn't be easier.</p>
<p>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:</p>
<div class="code panel" style="border-width: 1px;">
<div class="codeContent panelContent">
<pre class="code-java">
<span class="code-keyword">try</span> {
currentUser.login( token );
<span class="code-comment">//<span class="code-keyword">if</span> no exception, that's it, we're done!
</span>} <span class="code-keyword">catch</span> ( UnknownAccountException uae ) {
<span class="code-comment">//username wasn't in the system, show them an error message?
</span>} <span class="code-keyword">catch</span> ( IncorrectCredentialsException ice ) {
<span class="code-comment">//password didn't match, <span class="code-keyword">try</span> again?
</span>} <span class="code-keyword">catch</span> ( LockedAccountException lae ) {
<span class="code-comment">//account <span class="code-keyword">for</span> that username is locked - can't login. Show them a message?
</span>}
... more types exceptions to check <span class="code-keyword">if</span> you want ...
} <span class="code-keyword">catch</span> ( AuthenticationException ae ) {
<span class="code-comment">//unexpected condition - error?
</span>}
</pre>
</div>
</div>
<p>There are many different types of exceptions you can check, or throw your own for custom conditions Shiro might not
account for. See the <a class="external-link"
href="static/current/apidocs/org/apache/shiro/authc/AuthenticationException.html">AuthenticationException
JavaDoc</a> for more. </p>
<div class="panelMacro">
<table class="tipMacro">
<colgroup span="1">
<col span="1" width="24">
<col span="1">
</colgroup>
<tr>
<td colspan="1" rowspan="1" valign="top"><img align="middle"
src="https://cwiki.apache.org/confluence/images/icons/emoticons/check.png"
width="16" height="16" alt="" border="0"></td>
<td colspan="1" rowspan="1"><b>Handy Hint</b><br clear="none">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.
</td>
</tr>
</table>
</div>
<p>Ok, so by now, we have a logged in user. What else can we do?</p>
<p>Let's say who they are:</p>
<p></p>
<div class="code panel" style="border-width: 1px;">
<div class="codeContent panelContent">
<pre class="code-java">
<span class="code-comment">//print their identifying principal (in <span class="code-keyword">this</span> <span
class="code-keyword">case</span>, a username):
</span>log.info( <span class="code-quote">"User ["</span> + currentUser.getPrincipal() + <span class="code-quote">"] logged in successfully."</span> );
</pre>
</div>
</div>
<p>We can also test to see if they have specific role or not:</p>
<p></p>
<div class="code panel" style="border-width: 1px;">
<div class="codeContent panelContent">
<pre class="code-java">
<span class="code-keyword">if</span> ( currentUser.hasRole( <span class="code-quote">"schwartz"</span> ) ) {
log.info(<span class="code-quote">"May the Schwartz be with you!"</span> );
} <span class="code-keyword">else</span> {
log.info( <span class="code-quote">"Hello, mere mortal."</span> );
}
</pre>
</div>
</div>
<p>We can also see if they have a permission to act on a certain type of entity:</p>
<p></p>
<div class="code panel" style="border-width: 1px;">
<div class="codeContent panelContent">
<pre class="code-java">
<span class="code-keyword">if</span> ( currentUser.isPermitted( <span class="code-quote">"lightsaber:weild"</span> ) ) {
log.info(<span class="code-quote">"You may use a lightsaber ring. Use it wisely."</span>);
} <span class="code-keyword">else</span> {
log.info(<span class="code-quote">"Sorry, lightsaber rings are <span class="code-keyword">for</span> schwartz masters only."</span>);
}
</pre>
</div>
</div>
<p>Also, we can perform an extremely powerful <em>instance-level</em> permission check - the ability to see if the user
has the ability to access a specific instance of a type:</p>
<p></p>
<div class="code panel" style="border-width: 1px;">
<div class="codeContent panelContent">
<pre class="code-java">
<span class="code-keyword">if</span> ( currentUser.isPermitted( <span class="code-quote">"winnebago:drive:eagle5"</span> ) ) {
log.info(<span
class="code-quote">"You are permitted to 'drive' the 'winnebago' with license plate (id) 'eagle5'. "</span> +
<span class="code-quote">"Here are the keys - have fun!"</span>);
} <span class="code-keyword">else</span> {
log.info(<span class="code-quote">"Sorry, you aren't allowed to drive the 'eagle5' winnebago!"</span>);
}
</pre>
</div>
</div>
<p>Piece of cake, right?</p>
<p>Finally, when the user is done using the application, they can log out:</p>
<p></p>
<div class="code panel" style="border-width: 1px;">
<div class="codeContent panelContent">
<pre class="code-java">
currentUser.logout(); <span class="code-comment">//removes all identifying information and invalidates their session too.</span>
</pre>
</div>
</div>
<p>Well, that's the core to using Apache Shiro at the application-developer level. And although there is some pretty
sophisticated stuff going on under the hood to make this work so elegantly, that's really all there is to it.</p>
<p>But you might ask yourself, "But who is responsible for getting the user data during a login (usernames and
passwords, role and permissions, etc), and who actually performs those security checks during runtime?" Well, you
do, by implementing what Shiro calls a <a href="realm.html" title="Realm">Realm</a> and plugging that <tt>Realm</tt>
into Shiro's configuration. </p>
<p>However, how you configure a <a href="realm.html" title="Realm">Realm</a> is largely dependent upon your runtime
environment. For example, if you run a standalone application, or if you have a web based application, or a Spring
or JEE container-based application, or combination thereof. That type of configuration is outside the scope of this
QuickStart, since its aim is to get you comfortable with the API and Shiro's concepts.</p>
<p>When you're ready to jump in with a little more detail, you'll definitely want to read the <a
href="java-authentication-guide.html" title="Java Authentication Guide">Authentication Guide</a> and <a
href="java-authorization-guide.html" title="Java Authorization Guide">Authorization Guide</a>. Then can move
onto other <a href="documentation.html" title="Documentation">Documentation</a>, in particularly the <a
href="reference.html" title="Reference">Reference Manual</a>, to answer any other questions. You'll also
probably want to join the user <a href="mailing-lists.html" title="Mailing Lists">mailing list</a> - you'll find
that we have a great community with people willing to help whenever possible.</p>
<p>Thanks for following along. We hope you enjoy using Apache Shiro!</p>