Writing in the front

Security has always been the top priority. As Web developers, they should learn to use the right security framework to provide enough guarantee for their Application. Since most of my development projects are based on Spring and supplemented by Netty, I originally wanted to learn Spring Security, but then I looked at Shiro. By contrast, Shiro has the following advantages:

1. Simple 2. Applicable to non-Spring projectsCopy the code

So I decided to learn Shiro first and consider Spring Security when the technology is ready.

Shiro is introduced

Shiro features

Authentication

Validation. Similar to the “login” operation in Web applications, determine the user identity.

Authorization

Authorization. Access Control C. Restrict the actions of logged in users, such as whether they can access a web page.

SessionManager

Manage user-specific sessions, even in non-Web applications.

Cryptography

Cryptography, which provides password support and ensures that data sources use encryption algorithms while maintaining ease of use.

Shiro architecture

Higher level overview

Subject

A Subject is a security-specific “view” of the user currently performing an action. The user does not have to be a real person, but can be a third-party service or other application.

Subject instances are all bound to a SecurityManager, and when you interact with a Subject, you’re actually interacting with the SecurityManager.

SecurityManager

The core of Shiro is an “umbrella” that organizes all internal components to perform security operations. Once a SecurityManager has been configured to an application, let it go and the developer can focus most of his energy on interacting with the Subject.

Remember that when you interact with the Subject, the SecurityManager is actually handling the actual operations.

Realms

The domain. Realms serves as a bridge between Shiro and application security data (that is, data in the database that needs to be secured). When it comes to actually working with secure data, Shiro uses Realms to handle it. You can think of Realms as a security-specific DAO component that encapsulates the actual data source and provides Shiro with data when needed. When configuring authentication/authorization, you must specify at least one of these DAO components.

Shiro also provides Realms connections out of the framework, so that you can inject any data source connections you want.

Just like any other component, SecurityManager manages Realms to enable access to and use of secure identity data.

A more detailed level of structure

Subject

Security-specific “views” of the entities currently interacting with the application. (What a mouthful! A security-specific ‘view’ of the entity (user, 3rd-party service, cron job, etc) currently interacting with the software.)

SecurityManager

The core of Shiro’s framework, which manages and schedules components within Shiro, also manages Shiro’s “view” of each user, so it knows how to provide secure operations for each user.

Authenticator

Authenticator that acts on the user trying to log in. The authenticator also knows how to select a Realm to retrieve information about the user.

Authentication Strategy

If more than one Realm is configured, the AuthenticationStrategy federates multiple realms to enforce a specific AuthenticationStrategy.

Authorizer

Authorization. Provides a domain accessible to a specified user, like an authenticator, that can access back-end data and then process access control.

SessionManager

Provides enhanced session operations for sessions, even in non-Web domains. It tries to use existing session mechanisms, such as Servlet containers. If not, it provides a built-in mechanism to do so.

SessionDao

Perform persistent operations (CRUD) on behalf of SessionManager, or inject external data sources.

CacheManager

Cache management. Is responsible for managing the cache used by Shiro components, because many access operations preferentially access the cache, so the quality of the cache greatly affects the performance of the program. Any open source caching framework can be injected into Shiro.

Cryptography

Shiro encapsulates a number of easy-to-use and easy-to-understand cryptographic encryption, hashing, codec implementation classes. Shiro aims to make cryptography easy for ordinary people with normal intelligence to use (not that I’m saying, that’s exactly what it says on the website).

Realms

Bridge Shiro to the database.

SecurityManager

The SecurityManager and components use Java Bean editing, and those frameworks that use Bean management can use Shiro’s beans directly.

design

Shiro terms

Authentication

Is a validation process — confirming the identity of the subject to ensure relevant interactions with it.

Authorization

Also known as access control, it is the process of deciding what a user /subject can do or access to what resources.

Cipher

A password is an algorithm used for encryption or decryption. The algorithm is based on a piece of information called a key, and encryption varies by key, so decryption is difficult without a key. There are many ciphers, for example, block ciphers that act on signal blocks are usually of a fixed size. The stream cipher acts on a continuous stream signal. Symmetric passwords use the same key for encryption and decryption, whereas asymmetric passwords use different keys for encryption and decryption. If a key cannot be derived from another password, create public/private key-value pairs that can be shared.

Credential

The credentials. A credential is a piece of information that can be used to verify the identity of a user /subject. Typically, a credential is presented along with a principal during certification. Credentials are generally confidential information known only to a certain user /subject, such as passwords, PGP, biometric attributes, or similar mechanisms.

It is designed so that only one person knows the credentials that correspond exactly to a criterion. For the system, if a user /subject can provide a credential that matches the quasi-side stored in the system, it can authenticate that the user /subject is available. The degree of trust of the user /subject depends on the security of the credential (e.g., biometric information > password).

Cryptography

Cryptography. Cryptography is about protecting information from unexpected access, for example by hiding or transforming it into something else that may seem meaningless. Shiro uses two main approaches to cryptography: encrypting passwords with public or private keys, such as email addresses; Use hashes to encrypt irreversibly, such as passwords.

Hash

Hash. Hash functions are used to perform one-way, irreversible encryption of an input source (sometimes called a message). Encrypted into an encoded hash value (sometimes called a message digest). Often used for passwords, digital fingerprints, or low-level bit arrays.

Permission

The license. Just a statement that describes functionality, as Shiro describes it. They are the lowest level implementations of security policies, and they only define “what” an application can do, not “who” can do it. Permissions are simply statements of behavior, for example:

1. Open the file. 2'/user/list'Web page 3. Print documents 4. Delete'Jhon'The userCopy the code

Principal

A guideline can be any identity attribute of the applied user /subject. Anything that makes sense to the application is ok, such as username, first name, working name, Social security code (ID number), user ID, etc.

Shiro points out that every application user has a “master rule”, which can be any property but must be unique, ideally corresponding to the primary key in the database.

Realm

Think of it as a DAO component specific to secure data. The ability to access your application-specific data and then return it to Shiro so that no matter how many data sources you configure or how your database operations are written, Shiro provides a unified API for easy to understand operations.

Realm typically has a one-to-one data source correspondence, a Realm interface implementation class that uses sources-specific data apis to find authentication data (roles, permissions, etc.), such as JDBC, file IO, Hibernate, or JPA, or any other data access API.

Role

The definition of the role, so to speak, is very vague. Shiro sees it this way: A Role is a collection of permissions that contains multiple permission statements, and if you write your application according to Shiro’s definition, ho ho, you’ll find that you’re much more comfortable controlling security policies.

Session

Session is the data context generated during the interaction between the user /subject and the application. One user/Subject corresponds to one Session. Data can be added, read, and removed from the Session. It can also be used again by an application at some point in the future. The Session is destroyed when the user exits or inactivates a timeout.

Similar to HTTP sessions, Shiro’s sessions can implement similar functionality and can be used in any environment, not just Servlet containers or EJB containers.

Subject

For abstractions of things that interact with an application, for example, a Subject can represent a person, a program, a service, other systems, etc.

Shiro references documents

The core

The Authentication (verification)

Shiro’s validation is based on Subject, as mentioned earlier. Let’s talk about the verification steps:

Collect the Principal and Credential of the Subject. 2. Submit the collected Principal and Credential for verification 3. Judge the verification resultsCopy the code

The first step is to collect the verification result. Here we use Username-Password as an example:

// How to create username and password
// This can be an HTML form submission (most common in back-end development) or a file read
UsernamePasswordToken token = new UsernamePasswordToken(username, password);

// Whether to enable "Remember me" mode, this mode will be detailed later
token.setRememberMe(true);
Copy the code

The second step is to submit the collected results for verification:

Subject currentUser = SecurityUtils.getSubject();

currentUser.login(token);
Copy the code

The third step is to process the result of the validation, because if the validation fails, an exception will be thrown, so try catch should be used:

try {
    currentUser.login(token);
} catch ( UnknownAccountException uae ) { ...
} catch ( IncorrectCredentialsException ice ) { ...
} catch ( LockedAccountException lae ) { ...
} catch( ExcessiveAttemptsException eae ) { ... }...catch your own ...
} catch ( AuthenticationException ae ) {
    //unexpected error?
}
// The validation is complete
Copy the code

Take a look at the specific verification process:

(Highlight only)

To put it bluntly:

The validator is customizable, and the validation strategy is self-implementing. A validation policy is accessed four times in a validation activity: before either field is invoked; Immediately before getAuthenticationInfo() is called in a separate field; Immediately after getAuthenticationInfo() is called in a separate field; After all the fields have been called. The validation policy is also responsible for integrating the execution results of the Realm and ultimately returning an AuthenticationInfo instance to indicate the final result of the validation.

Shiro default has three validation strategies: AtLeastOneSuccessfulStrategy, FirstSuccessfulStratrgy (only use the return value of the first domain as a result), AllSuccessfulStrategy. Use AtLeastOneSuccessfulStrategy by default.

Look at the difference between “Remember me” and “proven.” To put it bluntly, “authenticated” authentication is higher, and “Remember me” only works for normal interactions. For critical interactions, such as making a payment or modifying information, ask again for authentication, not “Remember me.”

Of course, after the user interaction, call the subject.logout() method to logout the user and redirect the user to the new interface, otherwise you won’t be able to clear the Cookie.

Authorization (Authorization)

Authorization, often referred to as access control. It is used to control user access. (Contains three main components: Permissions, Roles, and Users)

License (Permissions). Licensing is a core part of Shiro’s security strategy. Indicates what a Subject can do (perform actions, such as opening a file, adding data to a database, etc.). For permissions, we recommend that they be Resources and Actions based. They reflect behavior. Remember, they don’t reflect the user.

Permissions can also encapsulate roles, or they can be directly associated with specific users (subjects), or users encapsulated in “groups”.

Roles (a Role). A role is an entity that contains specific actions and responsibilities. Roles can be assigned to user accounts so that users can “do” or “not do” the actions specified by the role attributes.

There are two types of roles, implicit and explicit. Explicit roles provide more granular control over application access control, and we (not I, But Shiro) recommend using explicit roles.

Here is an article on resource-based access control, recommended reading.

The User (User). The user is actually the “who”, or Subject, who interacts with the application. In Shiro, this is Subject. Your application data model defines the behaviors that users can perform. Of course, assignment behaves in the same way as previously mentioned — assigning roles containing permissions to users or including user “groups” by directly binding permissions to users.

Shiro implements data interaction using Realm implementation classes that encapsulate the details of data retrieval.

Validation of the Subject

There are two ways to verify a Subject (actually three, but the third is not very common) : programmatic authorization (that is, write if-else statements to process it, for example: if password ==XXX, else…) Or JDK-based annotation validation. These two ways

Programmatic authorization

Take a look at the use of programmatic authorization, which consists of two forms: role-based authorization and permission-based authorization:

1. Role-based authorization

1.1. Role Check for typical usage!

Subject currentUser = SecurityUtils.getSubject();

if (currentUser.hasRole("administrator")) {
    //show the admin button 
} else {
    //don't show the button? Grey it out?
}
Copy the code
The method name usage
boolean hasRole(String roleName) Determines whether the role is included based on the role name
List<Boolean> hasRoles(List<String>) Returns a list of Boolean values for each role name
boolean hasAllRoles(Collection<String>) roleNames Returns true only if all roles are included

1.2. Role assertions take a look at usage:

Subject currentUser = SecurityUtils.getSubject();

//guarantee that the current user is a bank teller and 
//therefore allowed to open the account: 
currentUser.checkRole("bankTeller");
openBankAccount();
Copy the code

If the assertion fails (excluding this role), an exception is thrown, otherwise the program executes normally

The method name usage
checkRole(String RoleName) If yes, execute normally, otherwise throw exception
checkRoles(Collection<String> roleNames) An exception is thrown only when all are included
checkRoles(String… roleNames) Same function as above, but different input parameters

2. License based licensing

There are two ways to check permissions: A Permission class object as a parameter, and a Permission name as a parameter.

2.1.1. Class objects as parameters

This method USES an implementation of a org.. Apache shiro. Authz. Permission interface class object as a parameter. This allows for more granular control than using String as an argument, and allows you to be more precise about the type of Permission you need.

Take a look at the usage:

Permission printPermission = new PrinterPermission("laserjet4400n"."print");

Subject currentUser = SecurityUtils.getSubject();

if (currentUser.isPermitted(printPermission)) {
    //show the Print button 
} else {
    //don't show the button? Grey it out?
}
Copy the code

Available methods:

The method name describe
isPermitted(Permission p) Return true if the Subject is allowed to perform the behavior contained in the license, false otherwise
isPermitted(List perms) Returns a list of results corresponding to the order of arguments
isPermittedAll(Collection perms) True is returned only if all are satisfied

2.1.2. Name as parameter

The use of strings as arguments is easier to write than the use of objects as arguments, but the corresponding loss of type-safety and more elaborate custom permissions is not available.

Take a look at the usage:

Subject currentUser = SecurityUtils.getSubject();

if (currentUser.isPermitted("printer:print:laserjet4400n")) {
    //show the Print button
} else {
    //don't show the button? Grey it out?
}
Copy the code

The code above is almost a shortcut version of the following:

Subject currentUser = SecurityUtils.getSubject();

Permission p = new WildcardPermission("printer:print:laserjet4400n");

if (currentUser.isPermitted(p) {
    //show the Print button
} else {
    //don't show the button? Grey it out?
}
Copy the code

In actual use, often using the ‘:’ (colon) segmentation based String, in the org.. Apache shiro. Authz. Permission. There are defined in the WildcardPermission can be, is to use the String class often used as a parameter

Look again at the list of methods:

The method name describe
isPermitted(String perm) Determines whether a license is allowed to be executed
isPermitted(String… perms) Return result list
isPermittedAll(String… perms) Returns true only if all are satisfied

2.2. Permission assertion is the same as role based usage. If the assertion fails, throw an exception, otherwise continue:

Subject currentUser = SecurityUtils.getSubject();

//guarantee that the current user is permitted 
//to open a bank account: 
Permission p = new AccountPermission("open");
currentUser.checkPermission(p);
openBankAccount();
Copy the code

Or an assertion using String as an argument:

Subject currentUser = SecurityUtils.getSubject();

//guarantee that the current user is permitted 
//to open a bank account: 
currentUser.checkPermission("account:open");
openBankAccount();
Copy the code

Go straight to the list of methods!

Described the method name | checkPermission (Permission p) | was allowed to return true checkPermission (String perm) | CheckPermissions (Collection < Permission > perms) | when all the permits are allowed to return true checkPermissions (String… The same goes for perms) |

Annotation-based authorization Before using this approach, make sure you have configured an AOP proxy. There are different approaches for different agents, and unfortunately Shiro is not unified.

Here’s a look at different examples of AOP enabled

AspectJ

Spring

Guice

RequiresAuthentication annotations

This annotation restricts the annotated method to being accessible only by authenticated subjects.

@RequiresAuthentication
public void updateAccount(Account userAccount) {
    //this method will only be invoked by a
    //Subject that is guaranteed authenticated. }Copy the code

Equivalent to this:

public void updateAccount(Account userAccount) {
    if(! SecurityUtils.getSubject().isAuthenticated()) {throw newAuthorizationException(...) ; }//Subject is guaranteed authenticated here. }Copy the code

RequiresGuest

This annotation enables visitor mode, which is accessible only to subjects without validation or “remember me.

@RequiresGuest
public void signUp(User newUser) {
    //this method will only be invoked by a
    //Subject that is unknown/anonymous. }Copy the code

Is equal to:

public void signUp(User newUser) {
    Subject currentUser = SecurityUtils.getSubject();
    PrincipalCollection principals = currentUser.getPrincipals();
    if(principals ! =null && !principals.isEmpty()) {
        //known identity - not a guest:
        throw newAuthorizationException(...) ; }//Subject is guaranteed to be a 'guest' here. }Copy the code

RequiresPermissions

The annotation annotates methods that indicate that the Subject must have at least one license to execute its logic

@RequiresPermissions("account:create")
public void createAccount(Account account) {
    //this method will only be invoked by a Subject
    //that is permitted to create an account. }Copy the code

Is equal to:

public void createAccount(Account account) {
    Subject currentUser = SecurityUtils.getSubject();
    if(! subject.isPermitted("account:create")) {
        throw newAuthorizationException(...) ; }//Subject is guaranteed to be permitted here. }Copy the code

RequiresRoles

This annotation states that the Subject accessing this method must have all the roles in the parameter or an exception will be thrown

@RequiresRoles("administrator")
public void deleteUser(User user) {
    //this method will only be invoked by an administrator. }Copy the code

Is equal to:

public void deleteUser(User user) {
    Subject currentUser = SecurityUtils.getSubject();
    if(! subject.hasRole("administrator")) {
        throw newAuthorizationException(...) ; }//Subject is guaranteed to be an 'administrator' here. }Copy the code

RequiresUser

Because Shiro’s User is Subject, it is required that the Subject of the operation be validated or remembered.

@RequiresUser
public void updateAccount(Account account) {
    //this method will only be invoked by a 'user'
    //i.e. a Subject with a known identity. }Copy the code

Is equal to:

public void updateAccount(Account account) {
    Subject currentUser = SecurityUtils.getSubject();
    PrincipalCollection principals = currentUser.getPrincipals();
    if (principals == null || principals.isEmpty()) {
        //no identity - they're anonymous, not allowed:
        throw newAuthorizationException(...) ; }//Subject is guaranteed to have a known identity here. }Copy the code

Authorized sequence

Look at some actual verification process!

Numbers represent specific steps (old rule, just look at highlights)

Step 1: The program calls any of the Subject’s hasRole*, checkRole*, isPermitted*, or checkPermission* method variants.

The second step: The Subject instance is really more of a DelegatingSubject delegating to the SecurityManager and then calling the SecurityManager method variant of the same name, SecurityManager implements org. Apache. Shiro. Authz. Authorizer interface, this interface defines some specific authorization method.

Step 3: SecurityManager will forward or by using the method of the authorizer’s corresponding proxy to internal org.. Apache shiro. Authz. Examples of authorizer. The Authorizer instance is actually a ModularRealmAuthorizer that allows you to consolidate multiple realms and then perform authorization.

Step 4: Each configured Realm is scanned to see if they implement the same Authorizer interface. If so, Realm’s methods of the same name, hasRole*, checkRole*, isPermitted*, or checkPermission*, will be called

ModularRealmAuthorizer

As mentioned earlier, the SecurityManager actually implements business logic through its ModularRealmAuthorizer.

For each authorization operation, the ModularRealmAuthorizer iterates through its collection of Realms and then processes them in the order of iteration, using the following logic:

If a Realm implements the Authorizer interface, the next step is to call the Realm's method with the same name: hasRole*, checkRole*, isPermitted*, or checkPermission* If a Realm method throws an exception, the exception is propagated to the Subject, and iteration access terminates 1.2. If the returntrue, the program terminates and returnstrue, this is a kind of security policy (fog)Copy the code

For configuring the global PermissionResolver

When using String-based Permission checking, most Realm implementation classes convert String to a Permission instance. This is because permission is assumed to use implicit logic rather than equality checking. Shiro handles this using the PermissionResolver, which translates your String expression into a Permission instance. For this, Shiro using WildcardPermissionResolver default support, note that this class supports only the WildcardPermission can be String expressions of a class, if you want to customize their own PermissionResolver, Remember to configure Realm.

Note that if you want to configure a Realm to accept a custom PermissionResolver, make sure that Realm implements the PermisionResolverAware interface. Or explicitly set up the Realm using PermissionResolver.

Also, there is a RolePermissionResolver, which converts a role name into a collection of permissions that can then be used by Realm. You can configure the global RolePermissionResolver to Realm of all configuration, of course don’t forget to let Realm implementations RolePermisionResolverAware interface. Or explicitly set the RolePermissionResolver instance for a single Realm.

Realm (domain)

First, implicit assignment is not recommended. When setting domains to the SecurityManager, it is best to set them explicitly so that they are in order. The order of realms is important in authentication and authorization.

Before Realm’s actual authentication method: getAuthenticationInfo(token) is called; Its supporting methods are called to determine whether the tokens passed in can be processed, and if the Realm supports processing tokens in this format, the actual authentication takes place.

Take a look at a typical validation process:

Check the incoming token. 2. Get the user information from a data source (e.g. MySQL) based on the incoming principal. 3. Compare the token's credential 4. If a match is found, return an AuthenticationInfo instance that encapsulates the user information for Shiro to understand 5. If not, throw an exceptionCopy the code

Tip: Implementing Realm methods directly can be time-consuming and thankless. Try implementing the AuthorizingRealm abstract class, which implements most of the basic methods for you.

For credential validation, try using the CredentialsMatcher, which exists as a matcher. Shiro provides a simple CredentialsMatcher implementation, Examples include SimpleCredentialsMatcher and HashedCredentialsMatcher.

For their differences.

SimpleCredentialsMatcher provides a simple comparison strategy (such as String matching) that compares Strings, character arrays, byte arrays, files, and input streams.

HashedCredentialsMatcher hashes credential one way, which is much more secure than ordinary direct saving versus pure passwords. Shiro provides many fine-grained subclass implementations for HashedCredentialsMatcher.

Consider a simple HashedCredentialsMatcher usage:

import org.apache.shiro.crypto.hash.Sha256Hash;
import org.apache.shiro.crypto.RandomNumberGenerator;
importorg.apache.shiro.crypto.SecureRandomNumberGenerator; .// Use sha-256 encryption algorithm
RandomNumberGenerator rng = new SecureRandomNumberGenerator();
Object salt = rng.nextBytes(); // random number as "salt"

// Specify the number of hash iterations, encoding form, and "salt" value
String hashedPasswordBase64 = new Sha256Hash(plainTextPassword, salt, 1024).toBase64();

User user = new User(username, hashedPasswordBase64);

// Save the "salt" for later verification
user.setPasswordSalt(salt);
userDAO.create(user);
Copy the code

Finally, you should make sure that your Realm implementation returns an instance of SaltedAuthenticationInfo instead of regular AuthenticationInfo, SaltedAuthenticationInfo ensures that HashedCredentialsMatcher can get your “salt” value.

If you want to turn validation off, simply set all of Realm’s supported methods to false.

There are two types of authorization: role-based authorization and permission-based authorization

Role-based authorization When calling one of the overloaded hasRoles or checkRoles methods on a Subject:

1. Subject proxies the actual action to the SecurityManager to determine whether a given role is assigned. 2. The SecurityManager proxies requests to the Authorizer. 3. Iterate Authorizing realms one by one to verify that a role has been assigned to the Subject, and return if all authorization realms do not indicate that the role has been assigned to the SubjectfalseTo deny access. 4. The getRoles() method of AuthorizationInfo of the authorization domain to get all the roles assigned to this Subject. 5. Return if the role awaiting validation is found in the role list (the return value of getRoles())true.Copy the code

When overrides of any isPermitted() or checkPermission() methods are called in Subject:

1. The Subject will delegate the task of checking permission to the SecurityManager. 2. The SecurityManager proxies Authorizer. 3. Traverses all domains. If all domains do not authorize this permission, Subject's access is forbidden. Authorization domains use the following order for license checking: 4.1. First, it directly identifies all permissions assigned to a Subject by calling the getObjectPermissions() and getStringPermissions() methods on AuthorizationInfo and summarizing the results. 4.2. If the registered RolePermissionResolver, can by calling RolePermissionResolver. ResolvePermissionsInRole () based on all the roles assigned to the Subject retrieval Permissions.  4.3. For the summary of the results of 1 and 2, the implies() method is called to check whether the permissions imply checked permissions.Copy the code

Session Management

To enable the Session

Using sessions in Shiro is as simple as this:

Subject currentUser = SecurityUtils.getSubject();

Session session = currentUser.getSession();
session.setAttribute( "someKey", someValue);
Copy the code

Note that the getSession() method, if the method argument is true, creates a Session when there is no Session; if false, it returns null, which is true by default.

SessionManager

SessionManager, responsible for creating, deleting, updating and searching sessions in an application. By default Shiro uses the DefaultSessionManager to operate. Set the SessionManager through SecurityManager.

  1. Example Set the Session timeout period

The default timeout is 1 hour. You can set the new timeout in ms by setting the globalSessionTimeout property of SessionManager.

  1. Set the Session listener

You can set up listeners to respond to Session state changes (such as Session creation). The sessionListeners property of the SessionManager is a collection of Session listeners. By implementing the SessionListener interface or extending the SessionListenerAdapter class.

package org.apache.shiro.session;

public interface SessionListener {

  
    void onStart(Session session);

   
    void onStop(Session session);

   
    void onExpiration(Session session);
}

Copy the code
  1. The Session is stored

Session can be stored in hard disk, memory, relational database, NoSQL, etc. Session CRUD is responsible by SessionDAO. You can implement your own SessionDAO implementation and set it up through the SessionManager.

package org.apache.shiro.session.mgt.eis;

import org.apache.shiro.session.Session;
import org.apache.shiro.session.UnknownSessionException;

import java.io.Serializable;
import java.util.Collection;

public interface SessionDAO {

    Session readSession(Serializable sessionId) throws UnknownSessionException;

    void update(Session session) throws UnknownSessionException;

    void delete(Session session);

    Collection<Session> getActiveSessions(a);
}

Copy the code

It’s obvious, add, delete, change, check

But one thing, if you’re writing a Web application, you can’t use DefaultSessionManager, you can use DefaultWebSessionManager, and then you can set up the SessionDAO.

3.1. EHCache SessionDAO

It is highly recommended to enable EHCache because it automatically stores data on hard disks when memory is tight to ensure data integrity. EHCache can be used for all cache operations in addition to session operations unless you customize the SessionDAO. It is also a good choice if you need container-based clustering.

You can enable this function by setting the cacheManager property of the SecurityManager to the EHCache property.

Web applications generally use the container’s own Session management, so the SessionDAO may not work, so you should reconfigure the SessionManager to enable it.

If you want to use EHCache emanager to set EHCache, you may use ehcache.xml, the core configuration is as follows:

<cache name="shiro-activeSessionCache"
       maxElementsInMemory="10000"
       overflowToDisk="true"
       eternal="true"
       timeToLiveSeconds="0"
       timeToIdleSeconds="0"
       diskPersistent="true"
       diskExpiryThreadIntervalSeconds="600"/>
Copy the code

Make sure that overflowToDisk and Eternal are true, the latter ensuring that the cache will not be turned off accidentally.

3.2. Customize the Session ID

By default, the UUID tool of the JDK is used to generate Session ids. The SessionID generation strategy is defined by implementing the SessionIdGenerator interface.

  1. Session authentication and periodic verification

Sessions will be validated every time they are accessed (to check whether they have expired and need to be deleted). However, sessions that have not been accessed for a long time may not be validated. Therefore, a timer is required to check the Session storage every once in a while to see if it has expired and delete it. Check once an hour by default. SessionValidationScheduler is the default timer. Through SessionValidationScheduler interval attribute, then set the interval. Then through our SessionManager sessionValidationScheduler attribute to set the timer.

For some special cases, you can choose to keep sessions even if authentication fails, but you still have to remember to delete them manually! This is important, and disabling timer authentication is not the same thing as disabling delete. After disabling timer authentication, you must create your own timer to do similar work.

The Session cluster

here

Session and Subject status

Session can be used to store user authentication information and authentication status. This is useful at the “remember me” level. Subject = new subject.builder ().sessionId(sessionId).buildSubject(); To build the Subject based on the sessionId.

Through the SecurityManager. SubjectDAO. SessionStorageEvaluator. SessionStorageEnabled attribute set to false to disable the Subject stateful session storage.

The SessionStorageEvaluator interface also lets you specify whether to enable sessions for different visitors

public interface SessionStorageEvaluator {

    public boolean isSessionStorageEnabled(Subject subject);

}
Copy the code

Typical usage is as follows:

public boolean isSessionStorageEnabled(Subject subject) {
        boolean enabled = false;
        if (WebUtils.isWeb(Subject)) {
            HttpServletRequest request = WebUtils.getHttpRequest(subject);
            //set 'enabled' based on the current request.
        } else {
            //not a web request - maybe a RMI or daemon invocation?
            //set 'enabled' another way...
        }

        return enabled;
    }
Copy the code

Cryptography

The Web application

Additional support

integration

END