| <!DOCTYPE html> |
| <!-- |
| Licensed to the Apache Software Foundation (ASF) under one or more |
| contributor license agreements. See the NOTICE file distributed with |
| this work for additional information regarding copyright ownership. |
| The ASF licenses this file to You under the Apache License, Version 2.0 |
| (the "License"); you may not use this file except in compliance with |
| the License. You may obtain a copy of the License at |
| |
| http://www.apache.org/licenses/LICENSE- 2.0 |
| |
| Unless required by applicable law or agreed to in writing, software |
| distributed under the License is distributed on an "AS IS" BASIS, |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| See the License for the specific language governing permissions and |
| limitations under the License. |
| --> |
| <html lang="en"> |
| <head> |
| <meta charset="utf-8"/> |
| <title>Apache Shiro Authentication | Apache Shiro</title> |
| <meta name="viewport" content="width=device-width, initial-scale=1.0"> |
| <meta name="keywords" content='documentation'> |
| <meta name="generator" content="JBake"> |
| <meta name="google-site-verification" content="QIax6uT5UX3enoU0G8Pz2pXbQ45KaQuHZ3nCh9V27mw"> |
| <meta name="google-site-verification" content="ecFap6dWJgS_GCCtxmJQJ_nFYQhM6EgSpBPZDU7xsCE"> |
| <meta name="google-site-verification" content="gBTYOG8lMfNb_jrWrH3kFbudpEs_WrAJ2lb2-zLRaso"/> |
| <meta name="msvalidate.01" content="0B57EB46CBFAD8FD45008D2DB6B6C68C"> |
| |
| <meta property="og:title" content="Apache Shiro Authentication | Apache Shiro"/> |
| <meta property="og:type" content="article"/> |
| <meta name="twitter:card" content="summary" /> |
| <meta name="twitter:site" content="@ApacheShiro" /> |
| <meta property="article:modification_time" content="2010-03-18T00:00:00Z"/> |
| <meta property="article:tag" content='documentation'/> |
| <meta property="og:locale" content="en_US" /> |
| <meta property="og:url" content='https://shiro.apache.org/authentication.html'/> |
| <meta property="og:image" content='images/shiro-featured-image.png'/> |
| <meta property="og:image:width" content='1200'/> |
| <meta property="og:image:height" content='628'/> |
| <meta property="og:site_name" content="Apache Shiro"/> |
| |
| <!-- Le styles --> |
| <link href="css/bootstrap.min.css" rel="stylesheet"> |
| <link href="bootstrap-icons-1.5.0/bootstrap-icons.css" rel="stylesheet"> |
| <link href="css/asciidoctor.css" rel="stylesheet"> |
| <link href="css/base.css" rel="stylesheet"> |
| <link href="highlight.js-11.2.0/styles/default.min.css" rel="stylesheet"> |
| <link href="css/gh-pages/gh-fork-ribbon.css" rel="stylesheet"/> |
| |
| <!-- Fav and touch icons --> |
| <!--<link rel="apple-touch-icon-precomposed" sizes="144x144" href="../assets/ico/apple-touch-icon-144-precomposed.png"> |
| <link rel="apple-touch-icon-precomposed" sizes="114x114" href="../assets/ico/apple-touch-icon-114-precomposed.png"> |
| <link rel="apple-touch-icon-precomposed" sizes="72x72" href="../assets/ico/apple-touch-icon-72-precomposed.png"> |
| <link rel="apple-touch-icon-precomposed" href="../assets/ico/apple-touch-icon-57-precomposed.png">--> |
| <link rel="shortcut icon" href="favicon.ico"> |
| |
| <!-- Matomo --> |
| <script> |
| var _paq = window._paq = window._paq || []; |
| /* tracker methods like "setCustomDimension" should be called before "trackPageView" */ |
| _paq.push(['disableCookies']); |
| _paq.push(['trackPageView']); |
| _paq.push(['enableLinkTracking']); |
| (function() { |
| var u="//matomo.privacy.apache.org/"; |
| _paq.push(['setTrackerUrl', u+'matomo.php']); |
| _paq.push(['setSiteId', '2']); |
| var d=document, g=d.createElement('script'), s=d.getElementsByTagName('script')[0]; |
| g.async=true; g.src=u+'matomo.js'; s.parentNode.insertBefore(g,s); |
| })(); |
| </script> |
| <!-- End Matomo Code --> |
| </head> |
| <body> |
| <div id="top-bar"></div> |
| <a class="github-fork-ribbon right-top" href="https://github.com/apache/shiro" title="Fork me on GitHub">Fork me on GitHub</a> |
| |
| <div id="wrap"> |
| |
| <div class="masthead"> |
| <p class="lead"> |
| <a href="index.html"><img src="images/apache-shiro-logo.png" style="height:100px; width:auto; vertical-align: bottom; margin-top: 20px;" alt="Apache Shiro Logo"></a> |
| <span class="tagline">Simple. Java. Security.</span> |
| <a class="pull-right" href="https://www.apache.org/events/current-event.html"> |
| <img style="padding-top: 8px" src="https://www.apache.org/events/current-event-125x125.png" alt="Apache Software Foundation Event Banner"/> |
| </a> |
| </p> |
| </div> |
| |
| <!-- Fixed navbar --> |
| <nav class="navbar navbar-expand-lg navbar-light bg-light shadow-sm mb-4"> |
| <div class="container-fluid"> |
| <button class="navbar-toggler" type="button" data-bs-toggle="collapse" data-bs-target="#navbarSupportedContent" aria-controls="navbarSupportedContent" aria-expanded="false" aria-label="Toggle navigation"> |
| <span class="navbar-toggler-icon"></span> |
| </button> |
| |
| <div class="collapse navbar-collapse" id="navbarSupportedContent"> |
| <ul class="navbar-nav me-auto mb-2 mb-lg-0"> |
| <li class="nav-item"> |
| <a class="nav-link" href="get-started.html">Get Started</a> |
| </li> |
| <li class="nav-item"> |
| <a class="nav-link" href="documentation.html">Docs</a> |
| </li> |
| |
| <li class="nav-item dropdown"> |
| <a class="nav-link dropdown-toggle" href="#" id="navbarDropdown-webapps" role="button" data-bs-toggle="dropdown" aria-expanded="false"> |
| Web Apps |
| </a> |
| <ul class="dropdown-menu" aria-labelledby="navbarDropdown-webapps"> |
| <li><a class="dropdown-item" href="web.html">General</a></li> |
| <li><a class="dropdown-item" href="jaxrs.html">JAX-RS</a></li> |
| <li><a class="dropdown-item" href="jakarta-ee.html">Jakarta EE</a></li> |
| <li><hr class="dropdown-divider"></li> |
| <li><a class="dropdown-item" href="web-features.html">Features</a></li> |
| </ul> |
| </li> |
| |
| <li><a class="nav-link" href="features.html">Features</a></li> |
| |
| <!-- integrations --> |
| <li class="nav-item dropdown"> |
| <a class="nav-link dropdown-toggle" href="#" id="navbarDropdown-integrations" role="button" data-bs-toggle="dropdown" aria-expanded="false"> |
| Integrations |
| </a> |
| <ul class="dropdown-menu" aria-labelledby="navbarDropdown-integrations"> |
| <li><a class="dropdown-item" href="spring-boot.html">Spring</a></li> |
| <li><a class="dropdown-item" href="guice.html">Guice</a></li> |
| <li><hr class="dropdown-divider"></li> |
| <li><a class="dropdown-item" href="integration.html">Third-Party Integrations</a></li> |
| </ul> |
| </li> |
| |
| <!-- Community --> |
| <li class="nav-item dropdown"> |
| <a class="nav-link dropdown-toggle" href="#" id="navbarDropdown-community" role="button" data-bs-toggle="dropdown" aria-expanded="false"> |
| Community |
| </a> |
| <ul class="dropdown-menu" aria-labelledby="navbarDropdown-community"> |
| <li><a class="dropdown-item" href="forums.html">Community Forums</a></li> |
| <li><a class="dropdown-item" href="mailing-lists.html">Mailing Lists</a></li> |
| <li><a class="dropdown-item" href="articles.html">Articles</a></li> |
| <li><a class="dropdown-item" href="news.html">News</a></li> |
| <li><a class="dropdown-item" href="events.html">Events</a></li> |
| <li><hr class="dropdown-divider"></li> |
| <li><a class="dropdown-item" href="community.html">More</a></li> |
| </ul> |
| </li> |
| |
| <!-- About --> |
| <li class="nav-item dropdown"> |
| <a class="nav-link dropdown-toggle" href="#" id="navbarDropdown-about" role="button" data-bs-toggle="dropdown" aria-expanded="false"> |
| About |
| </a> |
| <ul class="dropdown-menu" aria-labelledby="navbarDropdown-about"> |
| <li><a class="dropdown-item" href="about.html">About</a></li> |
| <li><a class="dropdown-item" href="privacy-policy.html">Privacy Policy</a></li> |
| <li><a class="dropdown-item" href="security-reports.html">Vulnerability Reports</a></li> |
| </ul> |
| </li> |
| </ul> |
| |
| <ul class="d-flex justify-content-end navbar-nav mb-2 mb-lg-0"> |
| <!-- The ASF --> |
| <li class="nav-item dropdown"> |
| <a class="nav-link dropdown-toggle" href="#" id="navbarDropdown-asf" role="button" data-bs-toggle="dropdown" aria-expanded="false"> |
| Apache Software Foundation |
| </a> |
| <ul class="dropdown-menu" aria-labelledby="navbarDropdown-asf"> |
| <li><a class="dropdown-item" href="https://www.apache.org/">Apache Homepage</a></li> |
| <li><a class="dropdown-item" href="https://www.apache.org/licenses/">License</a></li> |
| <li><a class="dropdown-item" href="https://www.apache.org/foundation/sponsorship.html">Sponsorship</a></li> |
| <li><a class="dropdown-item" href="https://www.apache.org/foundation/thanks.html">Thanks</a></li> |
| <li><a class="dropdown-item" href="https://www.apache.org/security/">Security</a></li> |
| </ul> |
| </li> |
| </ul> |
| </div> |
| </div> |
| </nav> |
| |
| <div class="page-header"> |
| <h1>Apache Shiro Authentication</h1> |
| </div> |
| |
| |
| <div class="admonitionblock tip"> |
| <table> |
| <tbody> |
| <tr> |
| <td class="icon"> |
| <div class="title">Handy Hint</div> |
| </td> |
| <td class="content"> |
| <div class="title">Shiro v1 version notice</div> |
| <div class="paragraph"> |
| <p>As of 2024-02-28, Shiro v1 will soon be superseded by v2.<p> |
| </div> |
| </td> |
| </tr> |
| </tbody> |
| </table> |
| </div> |
| |
| <div id="toc" class="toc"> |
| <div id="toctitle">Table of Contents</div> |
| <ul class="sectlevel1"> |
| <li><a href="#authenticating_subjects">Authenticating Subjects</a> |
| <ul class="sectlevel2"> |
| <li><a href="#Authentication-AuthenticatingSubject-Step1">Step 1: Collect the Subject’s principals and credentials</a></li> |
| <li><a href="#Authentication-AuthenticatingSubject-Step2">Step 2: Submit the principals and credentials</a></li> |
| <li><a href="#Authentication-AuthenticatingSubject-Step3">Step 3: Handling Success or Failure</a></li> |
| </ul> |
| </li> |
| <li><a href="#Authentication-RememberedVsAuthenticated">Remembered vs. Authenticated</a> |
| <ul class="sectlevel2"> |
| <li><a href="#Authentication-RememberedVsAuthenticated-WhyTheDistinction">Why the distinction?</a></li> |
| <li><a href="#Authentication-RememberedVsAuthenticated-AnIllustratingExample">An illustrating example</a></li> |
| </ul> |
| </li> |
| <li><a href="#Authentication-LoggingOut">Logging Out</a></li> |
| <li><a href="#Authentication-AuthenticationSequence">Authentication Sequence</a> |
| <ul class="sectlevel2"> |
| <li><a href="#Authentication-AuthenticationSequence-Authenticator">Authenticator</a></li> |
| <li><a href="#Authentication-AuthenticationSequence-AuthenticationStrategy">AuthenticationStrategy</a></li> |
| <li><a href="#Authentication-AuthenticationSequence-RealmAuthenticationOrder">Realm Authentication Order</a></li> |
| </ul> |
| </li> |
| <li><a href="#Authentication-RealmAuthentication">Realm Authentication</a></li> |
| </ul> |
| </div> |
| <div id="preamble"> |
| <div class="sectionbody"> |
| <div class="imageblock text-center"> |
| <div class="content"> |
| <img src="/images/ShiroFeatures_Authentication.png" alt="Shiro features authentication graphic"> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Authentication is the process of identity verification - that is, proving a user actually is who they say they are.</p> |
| </div> |
| <div class="paragraph"> |
| <p>For a user to prove their identity, they need to provide some identifying information as well as some sort of proof of that identity that your system understands and trusts.</p> |
| </div> |
| <div class="paragraph"> |
| <p>This is done by submitting a user’s <em>principals</em> and <em>credentials</em> to Shiro to see if they match what is expected by the application.</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p><strong>Principals</strong> are a Subject’s 'identifying attributes'. |
| Principals can be anything that identifies a Subject, such as a first name (given name), last name (surname or family name), a username, Social Security Number, etc. |
| Of course things like family names are not very good at uniquely identifying a <code>Subject</code>, so the best principals to use for authentication are unique for an application - typically a username or email address.</p> |
| </li> |
| </ul> |
| </div> |
| <div class="admonitionblock note"> |
| <table> |
| <tr> |
| <td class="icon"> |
| <i class="fa icon-note" title="Note"></i> |
| </td> |
| <td class="content"> |
| <div class="paragraph"> |
| <div class="title">Primary Principal</div> |
| <p>While Shiro can represent any number of principals, Shiro expects an application to have exactly one 'Primary' principal - a single value that uniquely identifies the <code>Subject</code> within the application. |
| This is typically a username, email address or globally unique user id in most applications.</p> |
| </div> |
| </td> |
| </tr> |
| </table> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p><strong>Credentials</strong> are usually secret values known only by the <code>Subject</code> which are used as supporting evidence that they in fact 'own' the claimed identity. |
| Some common examples of credentials are passwords, biometric data such as fingerprints and retina scans, and X.509 certificates.</p> |
| </li> |
| </ul> |
| </div> |
| <div class="paragraph"> |
| <p>The most common example of a principal/credential pairing is that of a username and password. |
| The username is the claimed identity, and the password is the proof matching the claimed identity. |
| If a submitted password matches what is expected by the application, the application can largely assume that the user really is who they say they are because no-one else should know the same password.</p> |
| </div> |
| </div> |
| </div> |
| <div class="sect1"> |
| <h2 id="authenticating_subjects">Authenticating Subjects</h2> |
| <div class="sectionbody"> |
| <div class="paragraph"> |
| <p>The process of authenticating a <code>Subject</code> can effectively broken down into three distinct steps:</p> |
| </div> |
| <div class="olist arabic"> |
| <ol class="arabic"> |
| <li> |
| <p>Collect the Subject’s submitted principals and credentials</p> |
| </li> |
| <li> |
| <p>Submit the principals and credentials for authentication.</p> |
| </li> |
| <li> |
| <p>If the submission is successful, allow access, otherwise retry authentication or block access.</p> |
| </li> |
| </ol> |
| </div> |
| <div class="paragraph"> |
| <p>The following code demonstrates how Shiro’s API reflects these steps:</p> |
| </div> |
| <div class="sect2"> |
| <h3 id="Authentication-AuthenticatingSubject-Step1">Step 1: Collect the Subject’s principals and credentials</h3> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">//Example using most common scenario of username/password pair: |
| UsernamePasswordToken token = new UsernamePasswordToken(username, password); |
| |
| //"Remember Me" built-in: |
| token.setRememberMe(true);</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>In this particular case, we’re using the <a href="/static/current/apidocs/org/apache/shiro/authc/UsernamePasswordToken.html">UsernamePasswordToken</a>, supporting the most common username/password authentication approach. |
| This is an implementation of Shiro’s <a href="/static/current/apidocs/org/apache/shiro/authc/AuthenticationToken.html">org.apache.shiro.authc.AuthenticationToken</a> interface, which is the base interface used by Shiro’s authentication system to represent submitted principals and credentials.</p> |
| </div> |
| <div class="paragraph"> |
| <p>It is important to note here that Shiro does not care how you acquire this information: perhaps the data was acquired by a user submitting an HTML form, or maybe it was retrieved from an HTTP header, or perhaps it was read from a Swing or Flex GUI password form, or maybe via command line arguments. |
| The process of collecting information from an application end-user is completely decoupled from Shiro’s <code>AuthenticationToken</code> concept.</p> |
| </div> |
| <div class="paragraph"> |
| <p>You may construct and represent <code>AuthenticationToken</code> instances however you like - it is protocol agnostic.</p> |
| </div> |
| <div class="paragraph"> |
| <p>This example also shows that we have indicated that we wish Shiro to perform 'Remember Me' services for the authentication attempt. |
| This ensures that Shiro remembers the user identity if they return to the application at a later date. |
| We will cover Remember Me services in a later chapter.</p> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="Authentication-AuthenticatingSubject-Step2">Step 2: Submit the principals and credentials</h3> |
| <div class="paragraph"> |
| <p>After the principals and credentials have been collected and represented as an <code>AuthenticationToken</code> instance, we need to submit the token to Shiro to perform the actual authentication attempt:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">Subject currentUser = SecurityUtils.getSubject(); |
| |
| currentUser.login(token);</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>After acquiring the currently-executing <code>Subject</code>, we make a single <code><a href="/static/current/apidocs/org/apache/shiro/subject/Subject.html#login(org.apache.shiro.authc.AuthenticationToken)">login</a></code> call, passing in the <code>AuthenticationToken</code> instance we created earlier.</p> |
| </div> |
| <div class="paragraph"> |
| <p>An invocation to the <code>login</code> method effectively represents an authentication attempt.</p> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="Authentication-AuthenticatingSubject-Step3">Step 3: Handling Success or Failure</h3> |
| <div class="paragraph"> |
| <p>If the <code>login</code> method returns quietly, that’s it - we’re done! |
| The <code>Subject</code> has been authenticated. |
| The application thread can continue uninterrupted and all further calls to <code>SecurityUtils.getSubject()</code> will return the authenticated <code>Subject</code> instance, and any calls to <code>subject.<a href="/static/current/apidocs/org/apache/shiro/subject/Subject.html#isAuthenticated()">isAuthenticated()</a></code> will return <code>true</code>.</p> |
| </div> |
| <div class="paragraph"> |
| <p>But what happens if the login attempt failed? |
| For example, what if the end-user supplied an incorrect password, or accessed the system too many times and maybe their account is locked?</p> |
| </div> |
| <div class="paragraph"> |
| <p>Shiro has a rich runtime <a href="/static/current/apidocs/org/apache/shiro/authc/AuthenticationException.html"><code>AuthenticationException</code></a> hierarchy that can indicate exactly why the attempt failed. |
| You can wrap <code>login</code> in a <code>try/catch</code> block and catch any exception you wish and react to them accordingly. |
| For example:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">try { |
| currentUser.login(token); |
| } catch ( UnknownAccountException uae ) { ... |
| } catch ( IncorrectCredentialsException ice ) { ... |
| } catch ( LockedAccountException lae ) { ... |
| } catch ( ExcessiveAttemptsException eae ) { ... |
| } ... catch your own ... |
| } catch ( AuthenticationException ae ) { |
| //unexpected error? |
| } |
| |
| //No problems, continue on as expected...</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>If one of the existing exception classes do not meet your needs, custom <code>AuthenticationExceptions</code> can be created to represent specific failure scenarios.</p> |
| </div> |
| <div class="admonitionblock tip"> |
| <table> |
| <tr> |
| <td class="icon"> |
| <i class="fa icon-tip" title="Tip"></i> |
| </td> |
| <td class="content"> |
| <div class="paragraph"> |
| <div class="title">Login Failure Tip</div> |
| <p>While your code can react to specific exceptions and execute logic as necessary, a security best practice is to only show a generic failure message to an end user in the event of a failure, for example, "Incorrect username or password.". |
| This ensures no specific information is available to hackers that may be attempting an attack vector.</p> |
| </div> |
| </td> |
| </tr> |
| </table> |
| </div> |
| </div> |
| </div> |
| </div> |
| <div class="sect1"> |
| <h2 id="Authentication-RememberedVsAuthenticated">Remembered vs. Authenticated</h2> |
| <div class="sectionbody"> |
| <div class="paragraph"> |
| <p>As shown in the example above, Shiro supports the notion of "remember me" in addition to the normal login process. |
| It is worth pointing out at this time that Shiro makes a very precise distinction between a <em>remembered</em> Subject and an actual <em>authenticated</em> Subject:</p> |
| </div> |
| <div class="ulist"> |
| <ul> |
| <li> |
| <p><strong>Remembered</strong>: A remembered <code>Subject</code> is not anonymous and has a known identity (i.e. <code>subject.<a href="/static/current/apidocs/org/apache/shiro/subject/Subject.html#getPrincipals()">getPrincipals()</a></code> is non-empty). |
| But this identity is remembered from a previous authentication during a <strong>previous</strong> session. |
| A subject is considered remembered if <code>subject.<a href="/static/current/apidocs/org/apache/shiro/subject/Subject.html#isRemembered()">isRemembered()</a></code> returns <code>true</code>.</p> |
| </li> |
| <li> |
| <p><strong>Authenticated</strong>: An authenticated <code>Subject</code> is one that has been successfully authenticated (i.e. the <code>login</code> method was invoked without throwing an exception) <em>during the Subject’s current session</em>. |
| A subject is considered authenticated if <code>subject.<a href="/static/current/apidocs/org/apache/shiro/subject/Subject.html#isAuthenticated()">isAuthenticated()</a></code> returns <code>true</code>.</p> |
| </li> |
| </ul> |
| </div> |
| <div class="admonitionblock caution"> |
| <table> |
| <tr> |
| <td class="icon"> |
| <i class="fa icon-caution" title="Caution"></i> |
| </td> |
| <td class="content"> |
| <div class="paragraph"> |
| <div class="title">Mutually Exclusive</div> |
| <p>Remembered and authenticated states are mutually exclusive - a <code>true</code> value for one indicates a <code>false</code> value for the other and vice versa.</p> |
| </div> |
| </td> |
| </tr> |
| </table> |
| </div> |
| <div class="sect2"> |
| <h3 id="Authentication-RememberedVsAuthenticated-WhyTheDistinction">Why the distinction?</h3> |
| <div class="paragraph"> |
| <p>The word 'authentication' has a very strong connotation of <em>proof</em>. |
| That is, there is an expected <em>guarantee</em> that the <code>Subject</code> has proven they are who they say they are.</p> |
| </div> |
| <div class="paragraph"> |
| <p>When a user is only remembered from a previous interaction with the application, the state of proof no longer exists: the remembered identity gives the system an idea who that user probably is, but in reality, has no way of absolutely <em>guaranteeing</em> if the remembered Subject represents the expected user. |
| Once the subject is authenticated, they are no longer considered only remembered because their identity would have been verified during the current session.</p> |
| </div> |
| <div class="paragraph"> |
| <p>So although many parts of the application can still perform user-specific logic based on the remembered principals, such as customized views, it should typically never perform highly-sensitive operations until the user has legitimately verified their identity by executing a successful authentication attempt.</p> |
| </div> |
| <div class="paragraph"> |
| <p>For example, a check to see if a <code>Subject</code> can access financial information should almost always depend on <code>isAuthenticated()</code>, not <code>isRemembered()</code>, to guarantee an expected and verified identity.</p> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="Authentication-RememberedVsAuthenticated-AnIllustratingExample">An illustrating example</h3> |
| <div class="paragraph"> |
| <p>The following is a fairly common scenario that helps illustrate why the distinction between remembered and authenticated is important.</p> |
| </div> |
| <div class="paragraph"> |
| <p>Let’s say you’re using <a href="https://www.amazon.com">Amazon.com</a>. |
| You’ve logged-in successfully and have added a few books to your shopping cart. |
| But you have to run off to a meeting, but forget to log out. |
| By the time the meeting is over, it’s time to go home, and you leave the office.</p> |
| </div> |
| <div class="paragraph"> |
| <p>The next day when you come in to work, you realize you didn’t complete your purchase, so you go back to amazon.com. |
| This time, Amazon 'remembers' who you are, greets you by name, and still gives you some personalized book recommendations. |
| To Amazon, <code>subject.isRemembered()</code> would return <code>true</code>.</p> |
| </div> |
| <div class="paragraph"> |
| <p>But, what happens if you try to access your account to update your credit card information to make your book purchase? |
| While Amazon 'remembers' you (<code>isRemembered()</code> == <code>true</code>), it cannot guarantee that you are in fact you (for example, maybe a co-worker is using your computer).</p> |
| </div> |
| <div class="paragraph"> |
| <p>So before you can perform a sensitive action like updating credit card information, Amazon will force you to login, so they can guarantee your identity. |
| After you log in, your identity has been verified and to Amazon, <code>isAuthenticated()</code> would now be <code>true</code>.</p> |
| </div> |
| <div class="paragraph"> |
| <p>This scenario happens so frequently for many types of applications, so the functionality is built in to Shiro, so you can leverage it for your own application. |
| Now, whether you use <code>isRemembered()</code> or <code>isAuthenticated()</code> to customize your views and workflows is up to you, but Shiro will maintain this fundamental state in case you need it.</p> |
| </div> |
| </div> |
| </div> |
| </div> |
| <div class="sect1"> |
| <h2 id="Authentication-LoggingOut">Logging Out</h2> |
| <div class="sectionbody"> |
| <div class="paragraph"> |
| <p>The opposite of authenticating is releasing all known identifying state. |
| When the <code>Subject</code> is done interacting with the application, you can call <code>subject.<a href="/static/current/apidocs/org/apache/shiro/subject/Subject.html#logout()">logout()</a></code> to relinquish all identifying information:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">currentUser.logout(); //removes all identifying information and invalidates their session too.</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>When you call <code>logout</code>, any existing <code>Session</code> will be invalidated and any identity will be disassociated (e.g. in a web app, the RememberMe cookie will also be deleted).</p> |
| </div> |
| <div class="paragraph"> |
| <p>After a <code>Subject</code> logs-out, the <code>Subject</code> instance is considered anonymous again and, except for web applications, can be re-used for <code>login</code> again if desired.</p> |
| </div> |
| <div class="admonitionblock caution"> |
| <table> |
| <tr> |
| <td class="icon"> |
| <i class="fa icon-caution" title="Caution"></i> |
| </td> |
| <td class="content"> |
| <div class="paragraph"> |
| <div class="title">Web Application Notice</div> |
| <p>Because remembered identity in web applications is often persisted with cookies, and cookies can only be deleted before a Response body is committed, it is highly recommended to redirect the end-user to a new view or page immediately after calling <code>subject.logout()</code>. |
| This guarantees that any security-related cookies are deleted as expected. |
| This is a limitation of how HTTP cookies function and not a limitation of Shiro.</p> |
| </div> |
| </td> |
| </tr> |
| </table> |
| </div> |
| </div> |
| </div> |
| <div class="sect1"> |
| <h2 id="Authentication-AuthenticationSequence">Authentication Sequence</h2> |
| <div class="sectionbody"> |
| <div class="paragraph"> |
| <p>Until now, we’ve only looked at how to authenticate a <code>Subject</code> from within application code. |
| Now we’ll cover what happens inside Shiro when an authentication attempt occurs.</p> |
| </div> |
| <div class="paragraph"> |
| <p>We’ve taken our previous architecture diagram from the <a href="/architecture.html">Architecture</a> chapter, and left only the components relevant to authentication highlighted. |
| Each number represents a step during an authentication attempt:</p> |
| </div> |
| <div class="imageblock text-center"> |
| <div class="content"> |
| <img src="/images/ShiroAuthenticationSequence.png" alt="authentication flow diagram"> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p><strong>Step 1</strong>: Application code invokes the <code>Subject.login</code> method, passing in the constructed <code>AuthenticationToken</code> instance representing the end-user’s principals and credentials.</p> |
| </div> |
| <div class="paragraph"> |
| <p><strong>Step 2</strong>: The <code>Subject</code> instance, typically a <a href="/static/current/apidocs/org/apache/shiro/subject/support/DelegatingSubject.html"><code>DelegatingSubject</code></a> (or a subclass) delegates to the application’s <code>SecurityManager</code> by calling <code>securityManager.login(token)</code>, where the actual authentication work begins.</p> |
| </div> |
| <div class="paragraph"> |
| <p><strong>Step 3</strong>: The <code>SecurityManager</code>, being a basic 'umbrella' component, receives the token and simply delegates to its internal <a href="/static/current/apidocs/org/apache/shiro/authc/Authenticator.html"><code>Authenticator</code></a> instance by calling <code><a href="/static/current/apidocs/org/apache/shiro/authc/Authenticator.html#authenticate(org.apache.shiro.authc.AuthenticationToken)">authenticator.authenticate(token)</a></code>. |
| This is almost always a <a href="/static/current/apidocs/org/apache/shiro/authc/pam/ModularRealmAuthenticator.html"><code>ModularRealmAuthenticator</code></a> instance, which supports coordinating one or more <code>Realm</code> instances during authentication. |
| The <code>ModularRealmAuthenticator</code> essentially provides a <a href="https://en.wikipedia.org/wiki/Pluggable_Authentication_Modules">PAM</a>-style paradigm for Apache Shiro (where each <code>Realm</code> |
| is a 'module' in PAM terminology).</p> |
| </div> |
| <div class="paragraph"> |
| <p><strong>Step 4</strong>: If more than one <code>Realm</code> is configured for the application, the <code>ModularRealmAuthenticator</code> instance will initiate a multi-<code>Realm</code> authentication attempt utilizing its configured <a href="/static/current/apidocs/org/apache/shiro/authc/pam/AuthenticationStrategy.html"><code>AuthenticationStrategy</code></a>. |
| Before, during and after the <code>Realms</code> are invoked for authentication, the <code>AuthenticationStrategy</code> will be called to allow it to react to each Realm’s results. |
| We will cover <code>AuthenticationStrategies</code> soon.</p> |
| </div> |
| <div class="admonitionblock note"> |
| <table> |
| <tr> |
| <td class="icon"> |
| <i class="fa icon-note" title="Note"></i> |
| </td> |
| <td class="content"> |
| <div class="paragraph"> |
| <div class="title">Single-Realm Application</div> |
| <p>If only a single Realm is configured, it is called directly - there is no need for an <code>AuthenticationStrategy</code> in a single-Realm application.</p> |
| </div> |
| </td> |
| </tr> |
| </table> |
| </div> |
| <div class="paragraph"> |
| <p><strong>Step 5</strong>: Each configured <code>Realm</code> is consulted to see if it <code><a href="/static/current/apidocs/org/apache/shiro/realm/Realm.html#supports(org.apache.shiro.authc.AuthenticationToken)">supports</a></code> the submitted <code>AuthenticationToken</code>. |
| If so, the supporting Realm’s <code><a href="/static/current/apidocs/org/apache/shiro/realm/Realm.html#getAuthenticationInfo(org.apache.shiro.authc.AuthenticationToken)">getAuthenticationInfo</a></code> method will be invoked with the submitted <code>token</code>. |
| The <code>getAuthenticationInfo</code> method effectively represents a single authentication attempt for that particular <code>Realm</code>. |
| We will cover the <code>Realm</code> authentication behavior shortly.</p> |
| </div> |
| <div class="sect2"> |
| <h3 id="Authentication-AuthenticationSequence-Authenticator">Authenticator</h3> |
| <div class="paragraph"> |
| <p>As mentioned earlier, the Shiro <code>SecurityManager</code> implementations default to using a <a href="/static/current/apidocs/org/apache/shiro/authc/pam/ModularRealmAuthenticator.html"><code>ModularRealmAuthenticator</code></a> instance. |
| The <code>ModularRealmAuthenticator</code> equally supports applications with single Realm as well as those with multiple realms.</p> |
| </div> |
| <div class="paragraph"> |
| <p>In a single-realm application, the <code>ModularRealmAuthenticator</code> will invoke the single <code>Realm</code> directly. |
| If two or more Realms are configured, it will use an <code>AuthenticationStrategy</code> instance to coordinate how the attempt occurs. |
| We’ll cover AuthenticationStrategies below.</p> |
| </div> |
| <div class="paragraph"> |
| <p>If you wish to configure the <code>SecurityManager</code> with a custom <code>Authenticator</code> implementation, you can do so in <code>shiro.ini</code> for example:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="highlightjs highlight"><code class="language-ini hljs" data-lang="ini">[main] |
| ... |
| authenticator = com.foo.bar.CustomAuthenticator |
| |
| securityManager.authenticator = $authenticator</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Although in practice, the <code>ModularRealmAuthenticator</code> is probably suitable for most needs.</p> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="Authentication-AuthenticationSequence-AuthenticationStrategy">AuthenticationStrategy</h3> |
| <div class="paragraph"> |
| <p>When two or more realms are configured for an application, the <code>ModularRealmAuthenticator</code> relies on an internal <a href="/static/current/apidocs/org/apache/shiro/authc/pam/AuthenticationStrategy.html"><code>AuthenticationStrategy</code></a> component to determine the conditions for which an authentication attempt succeeds or fails.</p> |
| </div> |
| <div class="paragraph"> |
| <p>For example, if only one Realm authenticates an <code>AuthenticationToken</code> successfully, but all others fail, is the authentication attempt considered successful? |
| Or must all Realms authenticate successfully for the overall attempt to be considered successful? |
| Or, if a Realm authenticates successfully, is it necessary to consult other Realms further? |
| An <code>AuthenticationStrategy</code> makes the appropriate decision based on an application’s needs.</p> |
| </div> |
| <div class="paragraph"> |
| <p>An AuthenticationStrategy is a stateless component that is consulted 4 times during an authentication attempt (any necessary state required for these 4 interactions will be given as method arguments):</p> |
| </div> |
| <div class="olist arabic"> |
| <ol class="arabic"> |
| <li> |
| <p>before any of the Realms are invoked</p> |
| </li> |
| <li> |
| <p>immediately before an individual Realm’s <code>getAuthenticationInfo</code> method is called</p> |
| </li> |
| <li> |
| <p>immediately after an individual Realm’s <code>getAuthenticationInfo</code> method is called</p> |
| </li> |
| <li> |
| <p>after all the Realms have been invoked</p> |
| </li> |
| </ol> |
| </div> |
| <div class="paragraph"> |
| <p>Also, an <code>AuthenticationStrategy</code> is responsible for aggregating the results from each successful Realm and 'bundling' them into a single <a href="/static/current/apidocs/org/apache/shiro/authc/AuthenticationInfo.html"><code>AuthenticationInfo</code></a> representation. |
| This final aggregate <code>AuthenticationInfo</code> instance is what is returned by the <code>Authenticator</code> instance and is what Shiro uses to represent the `Subject’s final identity (aka Principals).</p> |
| </div> |
| <div class="admonitionblock note"> |
| <table> |
| <tr> |
| <td class="icon"> |
| <i class="fa icon-note" title="Note"></i> |
| </td> |
| <td class="content"> |
| <div class="paragraph"> |
| <div class="title">Subject Identity 'View'</div> |
| <p>If you use more than one Realm in your application to acquire account data from multiple data sources, the <code>AuthenticationStrategy</code> is ultimately responsible for the final 'merged' view of the Subject’s identity that is seen by the application.</p> |
| </div> |
| </td> |
| </tr> |
| </table> |
| </div> |
| <div class="paragraph"> |
| <p>Shiro has 3 concrete <code>AuthenticationStrategy</code> implementations:</p> |
| </div> |
| <table class="tableblock frame-all grid-all stretch"> |
| <colgroup> |
| <col style="width: 50%;"> |
| <col style="width: 50%;"> |
| </colgroup> |
| <thead> |
| <tr> |
| <th class="tableblock halign-left valign-top"><code>AuthenticationStrategy</code> class</th> |
| <th class="tableblock halign-left valign-top">Description</th> |
| </tr> |
| </thead> |
| <tbody> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><a href="/static/current/apidocs/org/apache/shiro/authc/pam/AtLeastOneSuccessfulStrategy.html"><code>AtLeastOneSuccessfulStrategy</code></a></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">If one (or more) Realms authenticate successfully, the overall attempt is considered successful. |
| If none authenticate successfully, the attempt fails.</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><a href="/static/current/apidocs/org/apache/shiro/authc/pam/FirstSuccessfulStrategy.html"><code>FirstSuccessfulStrategy</code></a></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">Only the information returned from the first successfully authenticated Realm will be used. |
| All further Realms will be ignored. |
| If none authenticate successfully, the attempt fails.</p></td> |
| </tr> |
| <tr> |
| <td class="tableblock halign-left valign-top"><p class="tableblock"><a href="/static/current/apidocs/org/apache/shiro/authc/pam/AllSuccessfulStrategy.html"><code>AllSuccessfulStrategy</code></a></p></td> |
| <td class="tableblock halign-left valign-top"><p class="tableblock">All configured Realms must authenticate successfully for the overall attempt to be considered successful. |
| If any one does not authenticate successfully, the attempt fails.</p></td> |
| </tr> |
| </tbody> |
| </table> |
| <div class="paragraph"> |
| <p>The <code>ModularRealmAuthenticator</code> defaults to the <strong><code>AtLeastOneSuccessfulStrategy</code></strong> implementation, as this is the most commonly desired strategy. |
| However, you could configure a different strategy if you wanted:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="highlightjs highlight"><code class="language-ini hljs" data-lang="ini">[main] |
| ... |
| authcStrategy = org.apache.shiro.authc.pam.FirstSuccessfulStrategy |
| |
| securityManager.authenticator.authenticationStrategy = $authcStrategy |
| |
| ...</code></pre> |
| </div> |
| </div> |
| <div class="admonitionblock tip"> |
| <table> |
| <tr> |
| <td class="icon"> |
| <i class="fa icon-tip" title="Tip"></i> |
| </td> |
| <td class="content"> |
| <div class="paragraph"> |
| <div class="title">Custom AuthenticationStrategy</div> |
| <p>If you wanted to create your own <code>AuthenticationStrategy</code> implementation yourself, you could use the <code><a href="/static/current/apidocs/org/apache/shiro/authc/pam/AbstractAuthenticationStrategy.html">org.apache.shiro.authc.pam.AbstractAuthenticationStrategy</a></code> as a starting point. |
| The <code>AbstractAuthenticationStrategy</code> class automatically implements the ''bundling''/aggregation behavior of merging the results from each Realm into a single <code>AuthenticationInfo</code> instance.</p> |
| </div> |
| </td> |
| </tr> |
| </table> |
| </div> |
| </div> |
| <div class="sect2"> |
| <h3 id="Authentication-AuthenticationSequence-RealmAuthenticationOrder">Realm Authentication Order</h3> |
| <div class="paragraph"> |
| <p>It is very important to point out that the <code>ModularRealmAuthenticator</code> will interact with Realm instances in <em>iteration</em> order.</p> |
| </div> |
| <div class="paragraph"> |
| <p>The <code>ModularRealmAuthenticator</code> has access to the <code>Realm</code> instances configured on the <code>SecurityManager</code>. |
| When performing an authentication attempt, it will iterate over that collection, and for each <code>Realm</code> that supports the submitted <code>AuthenticationToken</code>, invoke the Realm’s <code>getAuthenticationInfo</code> method.</p> |
| </div> |
| <div class="sect3"> |
| <h4 id="Authentication-AuthenticationSequence-AuthenticationStrategy-ImplicitOrdering">Implicit Ordering</h4> |
| <div class="paragraph"> |
| <p>When using Shiro’s INI configuration format, you should configure Realms <em>in the order you want them to process an <code>AuthenticationToken`</em>. For example, in `shiro.ini</code>, Realms will be consulted in the order in which they are defined in the INI file. |
| That is, for the following <code>shiro.ini</code> example:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="highlightjs highlight"><code class="language-ini hljs" data-lang="ini">blahRealm = com.company.blah.Realm |
| ... |
| fooRealm = com.company.foo.Realm |
| ... |
| barRealm = com.company.another.Realm</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>The <code>SecurityManager</code> will be configured with those three realms, and during an authentication attempt, <code>blahRealm</code>, <code>fooRealm</code>, and <code>barRealm</code> will be invoked <em>in that order</em>.</p> |
| </div> |
| <div class="paragraph"> |
| <p>This has basically the same effect as if the following line were defined:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">securityManager.realms = $blahRealm, $fooRealm, $barRealm</code></pre> |
| </div> |
| </div> |
| <div class="paragraph"> |
| <p>Using this approach, you don’t need to set the <code>securityManager's</code> <code>realms</code> property - every realm defined will automatically be added to the <code>realms</code> property.</p> |
| </div> |
| </div> |
| <div class="sect3"> |
| <h4 id="Authentication-AuthenticationSequence-AuthenticationStrategy-ExplicitOrdering">Explicit Ordering</h4> |
| <div class="paragraph"> |
| <p>If you want to explicitly define the order in which the realms will be interacted with, regardless of how they are defined, you can set the securityManager’s <code>realms</code> property as an explicit collection property. |
| For example, if using the definition above, but you wanted the <code>blahRealm</code> to be consulted last instead of first:</p> |
| </div> |
| <div class="listingblock"> |
| <div class="content"> |
| <pre class="highlightjs highlight"><code class="language-ini hljs" data-lang="ini">blahRealm = com.company.blah.Realm |
| ... |
| fooRealm = com.company.foo.Realm |
| ... |
| barRealm = com.company.another.Realm |
| |
| securityManager.realms = $fooRealm, $barRealm, $blahRealm |
| ...</code></pre> |
| </div> |
| </div> |
| <div class="admonitionblock warning"> |
| <table> |
| <tr> |
| <td class="icon"> |
| <i class="fa icon-warning" title="Warning"></i> |
| </td> |
| <td class="content"> |
| <div class="paragraph"> |
| <div class="title">Explicit Realm Inclusion</div> |
| <p>When you explicitly configure the <code>securityManager.realms</code> property, <strong>only</strong> the referenced realms will be configured on the <code>SecurityManager</code>. |
| This means you could define 5 realms in INI, but only actually use 3 if 3 are referenced for the <code>realms</code> property. |
| This is different from implicit realm ordering where all available realms will be used.</p> |
| </div> |
| </td> |
| </tr> |
| </table> |
| </div> |
| </div> |
| </div> |
| </div> |
| </div> |
| <div class="sect1"> |
| <h2 id="Authentication-RealmAuthentication">Realm Authentication</h2> |
| <div class="sectionbody"> |
| <div class="paragraph"> |
| <p>This chapter covers Shiro’s main workflow explaining how an authentication attempt occurs. |
| The internal workflow of what happens in a single realm as it is consulted during authentication (i.e. 'Step 5' above) is covered in the <a href="/realm.html">Realm</a> |
| chapter’s <a href="/realm.html#Realm-RealmAuthentication">Realm Authentication</a> section.</p> |
| </div> |
| </div> |
| </div> |
| <hr /> |
| |
| </div> |
| |
| <div class="footer-padding"></div> |
| |
| <div class="container-fluid pt-2 border-top" id="custom-footer"> |
| <footer class="row justify-content-between align-items-center"> |
| <div class=" col-md-5"> |
| <div class="copyright-footer justify-content-start"> |
| <a href="https://www.apache.org/foundation/contributing.html">Donate to the ASF</a> | |
| <a href="https://www.apache.org/licenses/LICENSE-2.0.html">License</a> |
| <p class="text-muted">Copyright © 2008-2024 The Apache Software Foundation</p> |
| </div> |
| </div> |
| |
| <div class="d-flex justify-content-center col-md-1"> |
| <a class="btn btn-social"><span class="social-icon social-twitter"><i class="bi bi-twitter"></i></span></a> |
| <a class="btn btn-social"><span class="social-icon social-facebook"><i class="bi bi-facebook"></i></span></a> |
| <a class="btn btn-social"><span class="social-icon social-linkedin"><i class="bi bi-linkedin"></i></span></a> |
| </div> |
| |
| <div class="d-flex justify-content-end col-md-4" id="editThisPage"> |
| <input type="hidden" id="ghEditPage" value="https://github.com/apache/shiro-site/edit/main/src/site/content/authentication.adoc"/> |
| </div> |
| |
| <div class="d-flex col-md-2 justify-content-end" style="position: relative"> |
| <div class="footer-shield"></div> |
| </div> |
| </footer> |
| </div> |
| |
| |
| <!-- Le javascript |
| ================================================== --> |
| <!-- Placed at the end of the document so the pages load faster --> |
| <script src="js/bootstrap.min.js"></script> |
| <script src="highlight.js-11.2.0/highlight.min.js"></script> |
| <script src="js/shiro.js"></script> |
| |
| <script> |
| docReady( |
| addPageEditLink() |
| ); |
| </script> |
| <script>hljs.highlightAll();</script> |
| |
| </body> |
| </html> |