Apache Shiro™ is a powerful and easy-to-use Java security framework that performs authentication, authorization, cryptography, and session management. With Shiro’s easy-to-understand API, you can quickly and easily secure any application – from the smallest mobile applications to the largest web and enterprise applications.
Welcome to Shiro!
Overview
Features
Apache Shiro is a comprehensive application security framework with many features. The following diagram shows where Shiro focuses its energy, and this reference manual will be organized similarly:
Shiro targets what the Shiro development team calls “the four cornerstones of application security” - Authentication, Authorization, Session Management, and Cryptography:
- Authentication: Sometimes referred to as ‘login’, this is the act of proving a user is who they say they are.
- Authorization: The process of access control, i.e. determining ‘who’ has access to ‘what’.
- Session Management: Managing user-specific sessions, even in non-web or EJB applications.
- Cryptography: Keeping data secure using cryptographic algorithms while still being easy to use.
There are also additional features to support and reinforce these concerns in different application environments, especially:
- Web Support: Shiro’s web support APIs help easily secure web applications.
- Caching: Caching is a first-tier citizen in Apache Shiro’s API to ensure that security operations remain fast and efficient.
- Concurrency: Apache Shiro supports multi-threaded applications with its concurrency features.
- Testing: Test support exists to help you write unit and integration tests and ensure your code will be secured as expected.
- “Run As”: A feature that allows users to assume the identity of another user (if they are allowed), sometimes useful in administrative scenarios.
- “Remember Me”: Remember users’ identities across sessions so they only need to log in when mandatory.
High-Level Overview
At the highest conceptual level, Shiro’s architecture has 3 primary concepts: the Subject
, SecurityManager
and Realms
. The following diagram is a high-level overview of how these components interact, and we’ll cover each concept below:
Subject: As we’ve mentioned in our Tutorial, the
Subject
is essentially a security specific ‘view’ of the the currently executing user. Whereas the word ‘User’ often implies a human being, aSubject
can be a person, but it could also represent a 3rd-party service, daemon account, cron job, or anything similar - basically anything that is currently interacting with the software.Subject
instances are all bound to (and require) aSecurityManager
. When you interact with aSubject
, those interactions translate to subject-specific interactions with theSecurityManager
.SecurityManager: The
SecurityManager
is the heart of Shiro’s architecture and acts as a sort of ’umbrella’ object that coordinates its internal security components that together form an object graph. However, once the SecurityManager and its internal object graph is configured for an application, it is usually left alone and application developers spend almost all of their time with theSubject
API.We will talk about the
SecurityManager
in detail later on, but it is important to realize that when you interact with aSubject
, it is really theSecurityManager
behind the scenes that does all the heavy lifting for anySubject
security operation. This is reflected in the basic flow diagram above.Realms: Realms act as the ‘bridge’ or ‘connector’ between Shiro and your application’s security data. When it comes time to actually interact with security-related data like user accounts to perform authentication (login) and authorization (access control), Shiro looks up many of these things from one or more Realms configured for an application.
In this sense a Realm is essentially a security-specific DAO: it encapsulates connection details for data sources and makes the associated data available to Shiro as needed. When configuring Shiro, you must specify at least one Realm to use for authentication and/or authorization. The
SecurityManager
may be configured with multiple Realms, but at least one is required.Shiro provides out-of-the-box Realms to connect to a number of security data sources (aka directories) such as LDAP, relational databases (JDBC), text configuration sources like INI and properties files, and more. You can plug-in your own Realm implementations to represent custom data sources if the default Realms do not meet your needs.
Like other internal components, the Shiro
SecurityManager
manages how Realms are used to acquire security and identity data to be represented asSubject
instances.
Detailed Architecture
The following diagram shows Shiro’s core architectural concepts followed by short summaries of each:
- Subject (
org.apache.shiro.subject.Subject
)
A security-specific ‘view’ of the entity (user, 3rd-party service, cron job, etc) currently interacting with the software. - SecurityManager (org.apache.shiro.mgt.SecurityManager)
As mentioned above, theSecurityManager
is the heart of Shiro’s architecture. It is mostly an ‘umbrella’ object that coordinates its managed components to ensure they work smoothly together. It also manages Shiro’s view of every application user, so it knows how to perform security operations per user. - Authenticator (org.apache.shiro.authc.Authenticator)
TheAuthenticator
is the component that is responsible for executing and reacting to authentication (log-in) attempts by users. When a user tries to log-in, that logic is executed by theAuthenticator
. TheAuthenticator
knows how to coordinate with one or moreRealms
that store relevant user/account information. The data obtained from theseRealms
is used to verify the user’s identity to guarantee the user really is who they say they are.- Authentication Strategy (org.apache.shiro.authc.pam.AuthenticationStrategy)
If more than oneRealm
is configured, theAuthenticationStrategy
will coordinate the Realms to determine the conditions under which an authentication attempt succeeds or fails (for example, if one realm succeeds but others fail, is the attempt successful? Must all realms succeed? Only the first?).
- Authentication Strategy (org.apache.shiro.authc.pam.AuthenticationStrategy)
- Authorizer (org.apache.shiro.authz.Authorizer)
TheAuthorizer
is the component responsible determining users’ access control in the application. It is the mechanism that ultimately says if a user is allowed to do something or not. Like theAuthenticator
, theAuthorizer
also knows how to coordinate with multiple back-end data sources to access role and permission information. TheAuthorizer
uses this information to determine exactly if a user is allowed to perform a given action. - SessionManager (org.apache.shiro.session.mgt.SessionManager)
TheSessionManager
knows how to create and manage userSession
lifecycles to provide a robust Session experience for users in all environments. This is a unique feature in the world of security frameworks - Shiro has the ability to natively manage user Sessions in any environment, even if there is no Web/Servlet or EJB container available. By default, Shiro will use an existing session mechanism if available, (e.g. Servlet Container), but if there isn’t one, such as in a standalone application or non-web environment, it will use its built-in enterprise session management to offer the same programming experience. TheSessionDAO
exists to allow any datasource to be used to persist sessions.- SessionDAO (org.apache.shiro.session.mgt.eis.SessionDAO)
TheSessionDAO
performsSession
persistence (CRUD) operations on behalf of theSessionManager
. This allows any data store to be plugged in to the Session Management infrastructure.
- SessionDAO (org.apache.shiro.session.mgt.eis.SessionDAO)
- CacheManager (org.apache.shiro.cache.CacheManager)
TheCacheManager
creates and managesCache
instance lifecycles used by other Shiro components. Because Shiro can access many back-end data sources for authentication, authorization and session management, caching has always been a first-class architectural feature in the framework to improve performance while using these data sources. Any of the modern open-source and/or enterprise caching products can be plugged in to Shiro to provide a fast and efficient user-experience. - Cryptography (org.apache.shiro.crypto.*)
Cryptography is a natural addition to an enterprise security framework. Shiro’scrypto
package contains easy-to-use and understand representations of crytographic Ciphers, Hashes (aka digests) and different codec implementations. All of the classes in this package are carefully designed to be very easy to use and easy to understand. Anyone who has used Java’s native cryptography support knows it can be a challenging animal to tame. Shiro’s crypto APIs simplify the complicated Java mechanisms and make cryptography easy to use for normal mortal human beings. - Realms (org.apache.shiro.realm.Realm)
As mentioned above, Realms act as the ‘bridge’ or ‘connector’ between Shiro and your application’s security data. When it comes time to actually interact with security-related data like user accounts to perform authentication (login) and authorization (access control), Shiro looks up many of these things from one or more Realms configured for an application. You can configure as manyRealms
as you need (usually one per data source) and Shiro will coordinate with them as necessary for both authentication and authorization.
The SecurityManager
Because Shiro’s API encourages a Subject
-centric programming approach, most application developers will rarely, if ever, interact with the SecurityManager
directly (framework developers however might sometimes find it useful). Even so, it is still important to know how the SecurityManager
functions, especially when configuring one for an application.
Design
As stated previously, the application’s SecurityManager
performs security operations and manages state for all application users. In Shiro’s default SecurityManager
implementations, this includes:
- Authentication
- Authorization
- Session Management
- Cache Management
- Realm coordination
- Event propagation
- “Remember Me” Services
- Subject creation
- Logout and more.
But this is a lot of functionality to try to manage in a single component. And, making these things flexible and customizable would be very difficult if everything were lumped into a single implementation class.
To simplify configuration and enable flexible configuration/pluggability, Shiro’s implementations are all highly modular in design - so modular in fact, that the SecurityManager implementation (and its class-hierarchy) does not do much at all. Instead, the SecurityManager
implementations mostly act as a lightweight ‘container’ component, delegating almost all behavior to nested/wrapped components. This ‘wrapper’ design is reflected in the detailed architecture diagram above.
While the components actually execute the logic, the SecurityManager
implementation knows how and when to coordinate the components for the correct behavior.
The SecurityManager
implementations and the components are also JavaBeans compatible, which allows you (or a configuration mechanism) to easily customize the pluggable components via standard JavaBeans accessor/mutator methods (get/set). This means the Shiro’s architectural modularity can translate into very easy configuration for custom behavior.
Easy Configuration
Because of JavaBeans compatibility, it is very easy to configure the SecurityManager
with custom components via any mechanism that supports JavaBeans-style configuration, such as Spring, Guice, JBoss, etc.
Terminology
- Authentication
Authentication is the process of verifying a Subject’s identity - essentially proving that someone really is who they say they are. When an authentication attempt is successful the application can trust that the subject is guaranteed to be who the application expects.
- Authorization
Authorization, also known as Access Control, is the process of determining if a user/Subject is allowed to do something or not. It is usually accomplished by inspecting and interpreting a Subject’s roles and permissions (see below) and then allowing or denying access to a requested resource or function.
Cipher
A cipher is an algorithm for performing encryption or decryption. The algorithm generally relies on a piece of information called a key. And the encryption varies based on the key so decyrption is extremely difficult without it.
Ciphers come in different variations. Block Ciphers work on blocks of symbols usually of a fixed size while Stream Ciphers work on a continuous stream of symbols. Symmetric Ciphers use the same key for encryption and decryption while Asymmetric Ciphers use different keys. And if a key in an asymmetric cipher cannot be derived from the other, then one can be shared publicly creating public/private key pairs.
Credential
A Credential is a piece of information that verifies the identity of a user/Subject. One (or more) credentials are submitted along with Principal(s) during an authentication attempt to verify that the user/Subject submitting them is actually the associated user. Credentials are usually very secret things that only a particular user/Subject would know, such as a password or a PGP key or biometric attribute or similar mechanism.
The idea is that for a principal, only one person would know the correct credential to ‘pair’ with that principal. If the current user/Subject provides the correct credential matching the one stored in the system, then the system can assume and trust that the current user/Subject is really who they say they are. The degree of trust increases with more secure credential types (e.g. biometric signature > password).
- Cryptography
Cryptography is the practice of protecting information from undesired access by hiding it or converting it into nonsense so no one else can read it. Shiro focuses on two core elements of Cryptography: ciphers that encrypt data like email using a public or private key, and hashes (aka message digests) that irreversibly encrypt data like passwords.
- Hash
A Hash function is a one-way, irreversible conversion of an input source, sometimes called the message, into an encoded hash value, sometimes called the message digest. It is often used for passwords, digital fingerprints, or data with an underlying byte array.
Permission
A Permission, at least as Shiro interprets it, is a statement that describes raw functionality in an application and nothing more. Permissions are the lowest-level constructs in security policies. They define only “What” the application can do. They do not describe “Who” is able to perform the actions. A Permission is only a statement of behavior, nothing more.
Some examples of permissions:
- Open a file
- View the ‘/user/list’ web page
- Print documents
- Delete the ‘jsmith’ user
Principal
A Principal is any identifying attribute of an application user (Subject). An ‘identifying attribute’ can be anything that makes sense to your application - a username, a surname, a given name, a social security number, a user ID, etc. That’s it - nothing crazy.
Shiro also references something we call a
Subject
’s primary principal. A Primary principal is any principal that uniquely identifies theSubject
across the entire application. Ideal primary principals are things like a username or a user ID that is a RDBMS user table primary key. There is only one primary principal for users (Subjects) in an application.
Realm
A Realm is a component that can access application-specific security data such as users, roles, and permissions. It can be thought of as a security-specific DAO (Data Access Object). The Realm translates this application-specific data into a format that Shiro understands so Shiro can in turn provide a single easy-to-understand Subject programming API no matter how many data sources exist or how application-specific your data might be.
Realms usually have a 1-to-1 correlation with a data source such as a relational database, LDAP directory, file system, or other similar resource. As such, implementations of the Realm interface use data source-specific APIs to discover authorization data (roles, permissions, etc), such as JDBC, File IO, Hibernate or JPA, or any other Data Access API.
Role
The definition of a Role can vary based on who you talk to. In many applications it is a nebulous concept at best that people use to implicitly define security policies. Shiro prefers to interpret a Role as simply a named collection of Permissions. That’s it - an application unique name aggregating one or more Permission declarations.
This is a more concrete definition than the implicit one used by many applications. If you choose to have your data model reflect Shiro’s assumption, you’ll find you will have much more power in controlling security policies.
Session
A Session is a stateful data context associated with a single user/Subject who interacts with a software system over a period of time. Data can be added/read/removed from the Session while the subject uses the application and the application can use this data later where necessary. Sessions are terminated when the user/Subject logs out of the application or when it times out due to inactivity.
For those familiar with the HttpSession, a Shiro
Session
serves the same purpose, except Shiro sessions can be used in any environment even if there is no Servlet container or EJB container available.
- Subject
A Subject is just fancy security term that basically means a security-specific ‘view’ of an application user. A Subject does not always need to reflect a human being though - it can represent an external process calling your application, or perhaps a daemon system account that executes something intermittently over a period of time (such as a cron job). It is basically a representation of any entity that is doing something with the application.
Core
Authentication
Authenticating Subjects
Collect the Subject’s principals and credentials
1
2
3
4//Example using most common scenario of username/password pair:
UsernamePasswordToken token = new UsernamePasswordToken(username, password);
//"Remember Me" built-in:
token.setRememberMe(true);Submit the principals and credentials
1
2
3Subject currentUser = SecurityUtils.getSubject();
currentUser.login(token);
- Handling Success or Failure
1 | try { |
Remembered vs. Authenticated
Mutually Exclusive
Remembered and authenticated states are mutually exclusive - a true
value for one indicates a false
value for the other and vice versa.
Remembered记住的是登录人信息,但是实际操作人不一定是本人,所以当涉及敏感信息时,还是推荐Authenticated重新认证
Logging Out
The opposite of authenticating is releasing all known identifying state. When the Subject
is done interacting with the application, you can call subject.
logout()
to relinquish all identifying information:
1 | currentUser.logout(); //removes all identifying information and invalidates their session too. |
When you call logout
, any existing Session
will be invalidated and any identity will be disassociated (e.g. in a web app, the RememberMe cookie will also be deleted).
After a Subject
logs-out, the Subject
instance is considered anonymous again and, except for web applications, can be re-used for login
again if desired.
Web Application Notice
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 subject.logout()
.
Authorization
授权是基于resources(door, file, customer, etc)和actions的 (open, read, delete, etc)
方法check会返回boolean,assertion会静默执行逻辑或抛出异常
- 基于角色,简单直观
- 基于权限,粒度更细,安全策略变化时,对源码的影响更小
- 基于object的,类型安全但略微笨重
- 基于string(Wildcard Permissions)的,简单易读,但类型不安全
需要先开启AOP支持
RequiresAuthentication
RequiresGuest
RequiresPermissions
RequiresRoles
RequiresUser