blob: 0c7f1b3da9249e99210042ec74fdcf9cd2a5b10f [file] [log] [blame]
<!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 JAX-RS Support | Apache Shiro</title>
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<meta name="keywords" content='documentation,jax-rs,integrations,web'>
<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 JAX-RS Support | 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="article:tag" content='jax-rs'/>
<meta property="article:tag" content='integrations'/>
<meta property="article:tag" content='web'/>
<meta property="og:locale" content="en_US" />
<meta property="og:url" content='https://shiro.apache.org/jaxrs.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 JAX-RS Support</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="preamble">
<div class="sectionbody">
<div class="paragraph">
<p>Apache Shiro&#8217;s JAX-RS support is built on top of the more general <a href="web.html">Servlet</a> support, and requires Shiro&#8217;s Servlet Filter to be setup. The Servlet Filter can be setup by using Shiro&#8217;s Servlet fragment, <code>web.xml</code> configuration, or programmatically.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="dependencies">Dependencies</h2>
<div class="sectionbody">
<div class="paragraph">
<p>Include the <code>shiro-servlet-plugin</code> and <code>shiro-jaxrs</code> dependencies in you application classpath (we recommend using a tool such as Apache Maven or Gradle to manage this).</p>
</div>
<ul class="nav nav-tabs" id="dependency-cli-tab" role="tablist">
<li class="nav-item" role="presentation">
<button
class="nav-link active"
id="maven-cli-tab"
data-bs-toggle="tab"
data-bs-target="#maven-cli"
type="button"
role="tab"
aria-controls="maven-cli"
aria-selected="true"
>Maven</button>
</li>
<li class="nav-item" role="presentation">
<button
class="nav-link"
id="gradle-cli-tab"
data-bs-toggle="tab"
data-bs-target="#gradle-cli"
type="button"
role="tab"
aria-controls="gradle-cli"
aria-selected="false"
>Gradle</button>
</li>
<li class="nav-item" role="presentation">
<button
class="nav-link"
id="sbt-cli-tab"
data-bs-toggle="tab"
data-bs-target="#sbt-cli"
type="button"
role="tab"
aria-controls="sbt-cli"
aria-selected="false"
>SBT</button>
</li>
<li class="nav-item" role="presentation">
<button
class="nav-link"
id="ivy-cli-tab"
data-bs-toggle="tab"
data-bs-target="#ivy-cli"
type="button"
role="tab"
aria-controls="ivy-cli"
aria-selected="false"
>Ivy</button>
</li>
<li class="nav-item" role="presentation">
<button
class="nav-link"
id="leiningen-cli-tab"
data-bs-toggle="tab"
data-bs-target="#leiningen-cli"
type="button"
role="tab"
aria-controls="leiningen-cli"
aria-selected="false"
>Leiningen</button>
</li>
<li class="nav-item" role="presentation">
<button
class="nav-link"
id="buildr-cli-tab"
data-bs-toggle="tab"
data-bs-target="#buildr-cli"
type="button"
role="tab"
aria-controls="buildr-cli"
aria-selected="false"
>Buildr</button>
</li>
</ul>
<div class="tab-content" id="dependency-cli-tab-content">
<div
class="tab-pane fade show active"
id="maven-cli"
role="tabpanel"
aria-labelledby="maven-cli-tab"
>
<pre><code class='xml language-xml'>&lt;dependency&gt;
&lt;groupId&gt;org.apache.shiro&lt;/groupId&gt;
&lt;artifactId&gt;shiro-servlet-plugin&lt;/artifactId&gt;
&lt;version&gt;2.0.0&lt;/version&gt;
&lt;/dependency&gt;
&lt;dependency&gt;
&lt;groupId&gt;org.apache.shiro&lt;/groupId&gt;
&lt;artifactId&gt;shiro-jaxrs&lt;/artifactId&gt;
&lt;version&gt;2.0.0&lt;/version&gt;
&lt;/dependency&gt;
</code></pre>
</div>
<div
class="tab-pane fade"
id="gradle-cli"
role="tabpanel"
aria-labelledby="gradle-cli-tab"
>
<pre><code class='groovy language-groovy'>compile 'org.apache.shiro:shiro-servlet-plugin:2.0.0'
compile 'org.apache.shiro:shiro-jaxrs:2.0.0'
</code></pre>
</div>
<div
class="tab-pane fade"
id="sbt-cli"
role="tabpanel"
aria-labelledby="sbt-cli-tab"
>
<pre><code class='scala language-scala'>libraryDependencies += "org.apache.shiro" % "shiro-servlet-plugin" % "2.0.0"
libraryDependencies += "org.apache.shiro" % "shiro-jaxrs" % "2.0.0"
</code></pre>
</div>
<div
class="tab-pane fade"
id="ivy-cli"
role="tabpanel"
aria-labelledby="ivy-cli-tab"
>
<pre><code class='xml language-xml'>&lt;dependency org="org.apache.shiro" name="shiro-servlet-plugin" rev="2.0.0"/&gt;
&lt;dependency org="org.apache.shiro" name="shiro-jaxrs" rev="2.0.0"/&gt;
</code></pre>
</div>
<div
class="tab-pane fade"
id="leiningen-cli"
role="tabpanel"
aria-labelledby="leiningen-cli-tab"
>
<pre><code class='clojure language-clojure'>[org.apache.shiro/shiro-servlet-plugin "2.0.0"]
[org.apache.shiro/shiro-jaxrs "2.0.0"]
</code></pre>
</div>
<div
class="tab-pane fade"
id="buildr-cli"
role="tabpanel"
aria-labelledby="buildr-cli-tab"
>
<pre><code class='groovy language-groovy'>'org.apache.shiro:shiro-servlet-plugin:jar:2.0.0'
'org.apache.shiro:shiro-jaxrs:jar:2.0.0'
</code></pre>
</div>
</div>
<div class="admonitionblock note">
<table>
<tr>
<td class="icon">
<i class="fa icon-note" title="Note"></i>
</td>
<td class="content">
This is not required if using Jakarta EE module
</td>
</tr>
</table>
</div>
<div class="paragraph">
<p>For information on other ways to set up the Apache Shiro Filter see the <a href="web.html">web documentation</a>.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="configuration">Configuration</h2>
<div class="sectionbody">
<div class="paragraph">
<p>There are two basic approaches used to define the authentication and authorization for your JAX-RS resources: paths defined statically in configuration, or via annotations on your resource.</p>
</div>
<div class="paragraph">
<p>If you are using <a href="guice.html">Guice</a> or <a href="spring.html">Spring</a> see those docs on how to configure Shiro.</p>
</div>
<div class="sect2">
<h3 id="paths_defined_in_shiro_ini">Paths defined in <code>shiro.ini</code></h3>
<div class="paragraph">
<p>Just like any other web application, your resources paths can be defined in a <code>shiro.ini</code> file. For example, to require resources under <code>/api/secured</code> to use basic authentication, your <code>[urls]</code> section would look like:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-ini hljs" data-lang="ini">[urls]
/api/secured/** = authcBasic</code></pre>
</div>
</div>
<div class="paragraph">
<p>See the <a href="web.html">web documentation</a> for more details.</p>
</div>
<div class="paragraph">
<p>The other, probably more popular, option is to use Shiro&#8217;s <a href="java-annotations-list.html">annotations</a> alongside other JAX-RS annotations on your resources. However, you <strong>MUST</strong> still define at least one path in your <code>shiro.ini</code> file.</p>
</div>
<div class="paragraph">
<p>The below code block will allow for basic authentication but NOT require it (via the <code>permissive</code> flag). This way all the resources under <code>/api</code> can optional require authentication and authorization based on annotations.</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-ini hljs" data-lang="ini">[urls]
/api/** = authcBasic[permissive]</code></pre>
</div>
</div>
</div>
<div class="sect2">
<h3 id="jakarta_ee_security_annotations_jsr_250">Jakarta EE Security Annotations (JSR-250)</h3>
<div class="paragraph">
<p>In addition to all Shiro annotations, Jax-RS module allows to specify Jakarta EE security annotations such as <code>@RolesAllowed</code>, <code>@DenyAll</code> and <code>@PermitAll</code> on your Jax-RS Endpoints.</p>
</div>
</div>
<div class="sect2">
<h3 id="principal_propagation]">Principal Propagation</h3>
<div class="paragraph">
<p>If calling remote EJBs, for example, the container security mechanism might interpret <code>java.security.Principal</code> and will error the remote EJB call as unauthenticated.
If Jax-RS is used in conjunction with the <a href="jakarta-ee.html">Jakarta EE</a> module, the principal propagation is configured by Jakarta EE. However, if Jax-RS module is used standalone, principal propagation can be disabled by adding a configuration property to the map as illustrated below:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">@ApplicationPath("/api")
public class JaxRsApplication extends Application {
@Override
public Map&lt;String, Object&gt; getProperties() {
return Map.of(SHIRO_WEB_JAXRS_DISABLE_PRINCIPAL_PARAM, Boolean.TRUE);
}
}</code></pre>
</div>
</div>
</div>
</div>
</div>
<div class="sect1">
<h2 id="example">Example</h2>
<div class="sectionbody">
<div class="paragraph">
<p>To create a simple example we can define a JAX-RS resource <code>HelloShiro</code>:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">@Path("/shiro")
public class HelloShiro {
@GET
@RequiresUser
public String sayHelloShiro() {
return "Hello!";
}
@GET
@Path("define")
@RequiresPermissions("hello:define")
public String defineShiro() {
return "Shiro is the Japanese term for a castle";
}
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>This resource has two end points, the first allows access by any logged-in user, the second any user with the <a href="permissions.html">permission</a> <code>hello:define</code>.</p>
</div>
<div class="paragraph">
<p>The corresponding JAX-RS Application class:</p>
</div>
<div class="listingblock">
<div class="content">
<pre class="highlightjs highlight"><code class="language-java hljs" data-lang="java">@ApplicationPath("/api")
public class ExampleApp extends Application {
@Override
public Set&lt;Class&lt;?&gt;&gt; getClasses() {
Set&lt;Class&lt;?&gt;&gt; classes = new HashSet&lt;&gt;();
// register the Shiro Feature
classes.add(ShiroFeature.class);
// register resources:
classes.add(HelloShiro.class);
return classes;
}
}</code></pre>
</div>
</div>
<div class="paragraph">
<p>The <code>ShiroFeature</code> does three things:</p>
</div>
<div class="ulist">
<ul>
<li>
<p>configures exception mapping from Shiro&#8217;s <code>AuthorizationException</code> to HTTP status codes (401 and 403)</p>
</li>
<li>
<p>exposes Shiro&#8217;s <code>Subject</code> as a <code>java.security.Principal</code> (<a href="jakarta-ee.html#principal_propagation">Principal Propagation</a>)</p>
</li>
<li>
<p>Configures processing of Shiro&#8217;s annotations</p>
</li>
</ul>
</div>
<div class="paragraph">
<p>In the above example, requests to either <code>/api/shiro</code> or <code>/api/shiro/define</code> will return an HTTP status of <code>401</code> if a user is not currently logged in. A request to <code>/api/shiro/define</code> made by a user without the <code>hello:define</code> will return a <code>403</code>.</p>
</div>
</div>
</div>
<div class="sect1">
<h2 id="want_to_see_more">Want to see more?</h2>
<div class="sectionbody">
<div class="paragraph">
<p>You can find portable JAX-RS application that runs with <a href="https://jersey.java.net/">Jersey</a>, <a href="https://resteasy.dev/">RestEasy</a> or <a href="https://cxf.apache.org">Apache CXF</a> in the <a href="https://github.com/apache/shiro/tree/main/samples">samples</a> directory on GitHub.</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>&nbsp;|&nbsp;
<a href="https://www.apache.org/licenses/LICENSE-2.0.html">License</a>&nbsp;
<p class="text-muted">Copyright &copy; 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/jaxrs.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>