Apache Shiro support for the Jersey JAX-RS implementation.
Shiro 1.4 has been
released and includes a new official JAX-RS module shiro-jaxrs
based on shiro-jersey
.
The official shiro-jaxrs
module offers feature parity with the generic JAX-RS
functionality of shiro-jersey
. The main difference is that shiro-jaxrs
does
not support the Jersey specific injections of shiro-jersey
.
See:
- Apache Shiro JAX-RS Support
- the source code
- SHIRO-392
- Example usage of the Shiro JAX-RS module (Wayback Machine)
Add the following dependencies to pom.xml
in an existing project already using Jersey:
<dependency>
<groupId>org.secnod.shiro</groupId>
<artifactId>shiro-jersey</artifactId>
<version>0.2.0</version>
</dependency>
Version compatibility:
Jersey | Shiro Jersey | Compatibility |
---|---|---|
3.x | 0.4.0-SNAPSHOT | Jakarta EE |
2.26- | 0.3.0 | Java EE |
2.0-2.25 | 0.2.0 | Java EE |
1.x | 0.1.1 | Java EE |
If you are upgrading from:
- Jersey 2.0-2.25, see the upgrade instructions.
- Jersey 1.x, see the upgrade instructions.
An example web application is provided complete with source code and web content.
The rest of this section describes how Shiro has been added to the example application.
Add the Shiro servlet filter in web.xml
:
<context-param>
<param-name>shiroConfigLocations</param-name>
<param-value>classpath:shiro.ini</param-value>
</context-param>
<listener>
<listener-class>org.apache.shiro.web.env.EnvironmentLoaderListener</listener-class>
</listener>
<filter>
<filter-name>ShiroFilter</filter-name>
<filter-class>org.apache.shiro.web.servlet.ShiroFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>ShiroFilter</filter-name>
<url-pattern>/*</url-pattern>
<dispatcher>REQUEST</dispatcher>
<dispatcher>FORWARD</dispatcher>
<dispatcher>INCLUDE</dispatcher>
<dispatcher>ERROR</dispatcher>
</filter-mapping>
Then register the following components in the JAX-RS application:
public class ApiApplication extends ResourceConfig {
public ApiApplication() {
register(org.apache.shiro.web.jaxrs.ShiroFeature.class);
register(new SubjectFactory());
}
}
Finally configure shiro.ini
in the default package on the classpath:
[main]
[users]
exampleuser = examplepassword, examplerole
[roles]
examplerole = something:readpermission
[urls]
/** = noSessionCreation, authcBasic
Real applications should of course not store users and passwords in the INI-file. See the Shiro configuration documentation.
This section describes the different alternatives for how Shiro can be used from JAX-RS.
JAX-RS resource classes and methods can be annotated with the standard Shiro annotations.
The authorization requirements can for example be declared with @RequiresPermissions
on JAX-RS resource classes /
methods:
@Path("/auth")
@Produces(MediaType.TEXT_PLAIN)
@RequiresPermissions("protected:read")
public class AuthResource {
@GET
public String get() {
return "OK";
}
@PUT
@RequiresPermissions("protected:write")
public String set(String value) {
return value;
}
}
The example above can be summarized as:
- HTTP GET access requires the user to have the permission
protected:read
- HTTP PUT access requires the user to have both permissions
protected:read
andprotected:write
Programmatic authorization is done by injecting the Shiro Subject as a method parameter:
@Path("/auth")
@Produces(MediaType.TEXT_PLAIN)
public class AuthResource {
@GET
public String get(@Auth Subject subject) {
subject.checkPermission("protected:read");
return "OK";
}
}
Injecting the Subject is just a convenience over calling SecurityUtils.getSubject().
Declarative and programmatic authorization are often combined when some permissions are static and some are dynamic:
@Path("/auth")
@Produces(MediaType.TEXT_PLAIN)
public class AuthResource {
@GET
@RequiresPermissions("static-permission")
public String get(@Auth Subject subject) {
subject.checkPermission(dynamicPermission());
return "OK";
}
}
Instead of using the Shiro Subject
class directly one can use an application specific user class for programmatic
authorization:
@Path("/auth")
@Produces(MediaType.TEXT_PLAIN)
public class AuthResource {
@GET
public String get(@Auth User user) {
user.checkBusinessRulePermission();
return "OK";
}
}
A custom User
class is a convenient way of implementing application
specific authorization based on business rules on the user's data.
More authorization as rules means less authorization as permissions and hence fewer permissions to maintain.
See:
- The example User class.
- The example UserFactory
which must be registered as a JAX-RS component.
- The class TypeFactory
can be extended for injection of custom classes with the
@Auth
annotation.
- The class TypeFactory
can be extended for injection of custom classes with the
AuthInjectionBinder
has been deleted. Remove its registration in
ResourceConfig.register()
.
These instructions assume that the JAX-RS application is a subclass of
org.glassfish.jersey.server.ResourceConfig
.
Note that JAX-RS component registration is done by ResourceConfig.register()
instead of javax.ws.rs.core.Application.getSingletons()
.
-
AuthorizationFilterFeature
replacesShiroResourceFilterFactory
Remove the configuration of
ShiroResourceFilterFactory
fromweb.xml
and registerAuthorizationFilterFeature
as a JAX-RS component. -
SubjectFactory
replacesSubjectInjectableProvider
-
TypeFactory
replacesAuthInjectableProvider
The integration tests for this project can be run as follows:
mvn -Pintegration-tests test -Dshiro.jersey=false
The default is to run the tests using the Apache Shiro JAX-RS support.
Alternatively, the old shiro-jersey
features can be enabled instead by setting shiro.jersey
to true
.