This is the fifth day of my participation in the August More text Challenge. For details, see:August is more challenging

Overview of Shiro

1.1 Rights management

1.1.1 Rights Management

Basically, all systems involving user participation should carry out permission management. Permission management belongs to the category of system security. Permission management realizes the control of users’ access to the system, and controls users’ access to and only the authorized resources according to security rules or security policies.

Rights management includes user identity authentication and authorization (authentication and authorization for short). A resource user that needs access control is authenticated. After passing the authentication, the user has the permission to access the resource.

1.1.2 Identity authentication

Identity authentication is the process of judging whether a user is a legitimate user. In the most common simple identity authentication mode, the system checks whether the user name and password entered by a user are consistent with the user name and password stored in the system to determine the user identity. For systems such as fingerprint, show the fingerprint; For a card swiping system such as a hardware Key, a card swiping is required.

1.1.3, authorization,

Authorization, or access control, controls who can access what resources. After identity authentication, the principal can access system resources only after being assigned permission. If the principal does not have permission to access some resources, he cannot access them

2.1 What is Shiro

    Apache Shiro ™is a powerful and easy-to-use Java security framework that performs authentication, authorization, cryptography, 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.

Apache Shiro is a security framework for Java. Shiro makes it very easy to develop applications that are good enough to be used not only in the Java ase environment but also in the JavaEE environment. Shiro can help with authentication, authorization, encryption, session management, integration with the Web, caching, and more.

2.2. Why learn Shiro

  1. Since Shiro extracts functions related to security authentication into a framework, shiro can quickly complete the development of functions such as authentication and authorization and reduce the system cost.
  2. Shiro is widely used. Shiro can run in Web applications, non-Web applications, clustered and distributed applications. More and more users are using Shiro.

Spring Security (formerly Acegi) is also an open source permission management framework in the Java domain, but Spring Security runs on Spring, while Shiro is relatively independent, mainly because Shiro is simple and flexible to use. So now more and more users are choosing Shiro.

2.3 basic functions

  1. Authentication

Identity authentication/login, verifying that the user has the appropriate identity;

  1. Authorization

Authorization, that is, permission authentication, to verify whether an authenticated user has a certain permission. That is, to determine whether a user can do something, for example, to verify whether a user has a role. Or fine-grained verification of whether a user has a certain permission on a resource;

  1. SessionManager

Session management, that is, after the user login is a session, before the exit, all its information is in the session; The session can be in a normal JavaSE environment or in a Web environment.

  1. Cryptography

Encryption, to protect the security of data, such as password encryption stored in the database, rather than plain text storage;

  1. WebSupport

Web support for easy integration into the Web environment;

  1. Caching

Cache. For example, after a user logs in, the user information and roles/permissions are not checked every time. This improves efficiency.

  1. Concurrency

Shiro supports concurrent validation of multi-threaded applications. If you start another thread in one thread, permissions are automatically propagated.

  1. Testing

Provide test support;

  1. Run As

Allowing a user to pretend to be another user (if they allow it);

  1. Remember Me

Remember me, this is a very common feature, that once you log in, you don’t have to log in the next time.

Note: Shiro does not maintain users or privileges; These need to be designed/provided by us; Then inject it into Shiro through the corresponding interface. About the design, the SSM integration in the back of Shiro to say oh

2.4. Architecture Description

  1. Subject

Subject is the Subject. External applications interact with Subject. Subject records the current operating user and understands the concept of user as the Subject of the current operation, which may be a user requesting through a browser or a running program. A Subject is an interface in Shiro that defines a number of methods related to authentication and authorization. External programs are authenticated by a Subject, which is authenticated and authorized by a SecurityManager

  1. SecurityManager

The SecurityManager is the core of Shiro and is responsible for the security management of all subjects. The Authentication and authorization of a Subject can be completed through the SecurityManager. Essentially, the SecurityManager implements authentication through the Authenticator, authorization through the Authorizer, and session management through the SessionManager.

SecurityManager is an interface that inherits from the Authenticator, Authorizer, and SessionManager interfaces.

  1. Authenticator

Authenticator certifier, namely the user identity authentication, the Authenticator is an interface, shiro provides ModularRealmAuthenticator implementation class, Through ModularRealmAuthenticator basically can satisfy most requirements, also can custom authentication.

  1. Authorizer

Authorizer: The user is authenticated by the Authorizer. When accessing the function, the user needs to check whether the user has the operation permission of the function through the Authorizer.

  1. Realm

A Realm is the equivalent of a datasource source. A Realm is used by the securityManager to obtain access to user permissions for security purposes. For example, if the user’s identity data is in a database, the Realm needs to obtain the user’s identity information from the database.

** Note: Don’t think of a realm as simply fetching data from a data source. There is also code for authentication, authorization, and validation within a realm. 支那

  1. sessionManager

SessionManager is session management. The Shiro framework defines a set of session management that does not depend on sessions in a Web container, so Shiro can be used for non-Web applications, or to manage sessions in a single point for distributed applications. This feature enables it to implement single sign-on.

  1. SessionDAO

The SessionDAO is a set of interfaces for session operations. For example, to store a session to a database, you can use JDBC to store the session to the database.

  1. CacheManager

CacheManager stores user permission data in the cache to improve performance.

  1. Cryptography

Shiro provides a suite of encryption/decryption components for easy development. For example, provide common hash, encryption/decryption and other functions.

Download Shiro and Maven dependencies

Shiro.apache.org/download.ht…

  • Shro-all is the shiro feature JAR package
  • Shro-core is shiro’s basic feature pack
  • Shiro – a package for web and Web integration
  • Shro-spring integrated package for Shrio and Spring

2. Basic Introduction to Shiro

2.1 Description of shiro. ini file

  1. InitializationFile (INI) Initial file. Window Indicates the extension of the system file.

  2. Shiro can be used with or without a database connection. If you do not connect to a database, you can configure static data in shiro.ini

2.2 components of the shrio. ini file

[main] : defines a global variable

  1. Built-in securityManager object.

  2. Write inside [main] when working with a built-in object

[main]SecurityManager. Property = Valuexiaolin=123456SecurityManager. Object property =$xiaolinCopy the code

[users] : Defines the user name and password

[users]
# set username to zhangsan and password to zs
zhangsan=zs
# define user name lisi password lisi with both role1 and role2 roles
lisi=lisi,role1,role2

Copy the code

[Roles] : Defines roles

[roles]
role1= permission name1And permissions2 
role2= permissions3And permissions4

Copy the code

[urls] : Defines which built-in urls work. Used in Web applications.

[urls]
#url = built-in filter or custom filter
# Url that appears /login when accessing must be authenticated. The Filter corresponding to authC is supported
/login=authc
No authentication is required for any URL.
/** = anon
All content must ensure that the user is logged in.
/**=user
You must ensure that the user has the role1 and Role2 roles.
/abc= roles [" role1, role2 "]Copy the code

2.3. Detailed explanation of filter

Filter name The filter class describe
anon org.apache.shiro.web.filter.authc.AnonymousFilter Anonymous filter
authc org.apache.shiro.web.filter.authc.FormAuthenticationFilter If you want to continue the operation, you need to perform the corresponding form authentication. Otherwise, the operation fails
authcBasic org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter Basic HTTP authentication filtering, if not, jump to the login page
logout org.apache.shiro.web.filter.authc.LogoutFilter Login logout Filter
noSessionCreation org.apache.shiro.web.filter.session.NoSessionCreationFilter No session created filter
perms org.apache.shiro.web.filter.authz.PermissionsAuthorizationFilter Permission filter
port org.apache.shiro.web.filter.authz.PortFilter Port filter, you can set whether to specify the port if not jump to the login page
rest org.apache.shiro.web.filter.authz.HttpMethodPermissionFilter HTTP method filters, which can be specified such as post cannot be accessed
roles org.apache.shiro.web.filter.authz.RolesAuthorizationFilter Role filter to determine whether the current user has specified a role
ssl org.apache.shiro.web.filter.authz.SslFilter The request needs to go through SSL, if not jump back to the login page
user org.apache.shiro.web.filter.authc.UserFilter If you access a known user, like the Remember me function, go through this filter

Anon: Anonymous processing filter, that is, no login required to access; Generally used for static resource filtering;

Such as: / static / * * = -anon

Authc: Indicates that authentication (login) is required.

Such as: / * * = authc

Roles: Role authorization filter that verifies whether users have resource roles.

Such as: / admin / * = roles/admin

Perms: Permission authorization filter that verifies whether a user has resource permissions.

Such as: / employee/input = perms [” user: the update “]

Logout: Logs out the filter

Such as: / logout = logout

Three, certification

3.1, certification

The authentication process is the user’s identity confirmation process, and the function is the familiar login authentication. The user enters the account and password and submits it to the background, and the background checks the correctness of the account and password by accessing the database.

3.2 Key objects in authentication

3.2.1,Subject: the Subject

The user who accesses the system can be a user or a program. Those who are authenticated are called bodies.

3.2.2,Principal: identity information

The id must be unique, such as the user name, mobile phone number, and email address. A Principal can have multiple identities, but it must have a Primary Principal.

3.2.3,Credential: Credential information

Is security information, such as passwords and certificates, known only to the principal.

3.3 Certification process

The final user comparison is performed by the doGetAuthenticationInfo method in the SimpleAccountRealm class, which validates the user name.

The final password verification is done in the assertCredentialsMatch method of the AuthenticatingRealm class and is automatic. We do not need to do it manually.

3.4 Code implementation

3.4.1 Importing dependencies

<dependency>
    <groupId>commons-logging</groupId>
    <artifactId>commons-logging</artifactId>
    <version>1.1.3</version>
</dependency>
<dependency>
    <groupId>org.apache.shiro</groupId>
    <artifactId>shiro-core</artifactId>
    <version>1.5.2</version>
</dependency>

<dependency>
    <groupId>junit</groupId>
    <artifactId>junit</artifactId>
    <version>4.13.2</version>
</dependency>
<dependency>
    <groupId>org.projectlombok</groupId>
    <artifactId>lombok</artifactId>
    <version>1.16.22</version>
    <scope>provided</scope>
</dependency>
Copy the code

3.4.2 Writing ini files

[users]
xiaolin=Awesome!
zs=13
Copy the code

3.4.3 Writing test classes

 /** * to test Shiro foundation */
  @Test
  public void testShiroBase(a){
    // Create Shiro security Manager, which is the core of Shiro
    DefaultSecurityManager securityManager = new DefaultSecurityManager();
    // Load the ini configuration file to get the user information configured in the configuration file
    IniRealm iniRealm = new IniRealm("classpath:shiro-authc.ini");
    // Inject a realm object into the securityManager
    securityManager.setRealm(iniRealm);
    // Inject the security manager into the current environment
    SecurityUtils.setSecurityManager(securityManager);
    // Get the Subject principal object, whether logged in or not
    Subject subject = SecurityUtils.getSubject();
    // Print the authentication status
    System.out.println("Authentication status"+subject.isAuthenticated());
    // Create a token that carries the account number and password
    UsernamePasswordToken token = new UsernamePasswordToken("xiaolin"."666");
    // Call subject to pass in the token for login
    subject.login(token);
    System.out.println("Authentication status"+subject.isAuthenticated());
  }
Copy the code

3.4.4, pay attention to

If the entered identity and credentials match those configured in the INI file, the login succeeds and the login status is true; otherwise, the login status is false.

There are several conditions for a login failure (exceptions thrown) :

  1. Account error:org.apache.shiro.authc.UnknownAccountException
  2. Password error:org.apache.shiro.authc.IncorrectCredentialsException

3.4.5 Shiro certification source code analysis

1. Call the Subject. login method for login, which will automatically delegate to the securityManager.login method for login; 2. The securityManager authenticates with the Authenticator; 3, the realization of the Authenticator class invokes ModularRealmAuthenticator realm from the ini configuration file user account and password, true is used here IniRealm (shiro bring, equivalent to a data source); 4, IniRealm first find the account according to the account of the token to the ini, if can’t find to ModularRealmAuthenticator returns null, if find the matching password, matching password authentication by success.

3.5 custom Realm

Custom realms are used a lot in real world development, and the account information we need to use usually comes from the application or database, rather than the configuration of the INI file we used earlier.

Call the doGetAuthenticationInfo method in the AuthenticatingRealm. If the returned info is not null, the account exists and the password verification is performed. If it doesn’t, it throws the UnknownAccountException.

So, if we want to customize the Realm, we should override the doGetAuthenticationInfo() method and implement the account verification in the method. And return the AuthenticationInfo object to the upper-level caller AuthenticatingRealm for further verification.

Realm provided by Shiro

3.5.2, SimpleAccountRealm

When we Debug, we can see that SimpleAccountRealm is used in the source code for authentication.

3.5.3, SimpleAccountRealm part of the source code

/ / certification
public class SimpleAccountRealm extends AuthorizingRealm {
		/ /... omit
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        UsernamePasswordToken upToken = (UsernamePasswordToken) token;
        SimpleAccount account = getUser(upToken.getUsername());

        if(account ! =null) {

            if (account.isLocked()) {
                throw new LockedAccountException("Account [" + account + "] is locked.");
            }
            if (account.isCredentialsExpired()) {
                String msg = "The credentials for account [" + account + "] are expired";
                throw newExpiredCredentialsException(msg); }}return account;
    }

    / / authorization
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        String username = getUsername(principals);
        USERS_LOCK.readLock().lock();
        try {
            return this.users.get(username);
        } finally{ USERS_LOCK.readLock().unlock(); }}}Copy the code

3.6 SSM integrated Shiro certification

3.6.1. Adding dependencies

<properties>
	<shiro.version>1.5.2</shiro.version>
</properties>
<! - shiro core -- -- >
<dependency>
    <groupId>org.apache.shiro</groupId>
    <artifactId>shiro-core</artifactId>
    <version>${shiro.version}</version>
</dependency>
<! -- Shiro Web module -->
<dependency>
    <groupId>org.apache.shiro</groupId>
    <artifactId>shiro-web</artifactId>
    <version>${shiro.version}</version>
</dependency>
<! -- Shiro and Spring integration -->
<dependency>
    <groupId>org.apache.shiro</groupId>
    <artifactId>shiro-spring</artifactId>
    <version>${shiro.version}</version>
</dependency>
<! -- EhCache cache used by Shiro -->
<dependency>
    <groupId>org.apache.shiro</groupId>
    <artifactId>shiro-ehcache</artifactId>
    <version>${shiro.version}</version>
</dependency>
<! -- Shiro dependent log package -->
<dependency>
    <groupId>commons-logging</groupId>
    <artifactId>commons-logging</artifactId>
    <version>1.2</version>
</dependency>
<! Freemarker's Shiro tag library -->
<dependency>
    <groupId>net.mingsoft</groupId>
    <artifactId>shiro-freemarker-tags</artifactId>
    <version>1.0.1</version>
</dependency>
Copy the code

3.6.2. Configure proxy Filters

When accessing, a series of pre-processing operations are required. Shiro chooses to use a filter to intercept this, because Shiro does not rely on the Spring container, so the absence of SpringMVC means that interceptors cannot be used, but filters are different and can be used for any Web project. We need to configure the filters in web.xml.

<filter>
    <filter-name>shiroFilter</filter-name>
    <filter-class>
        org.springframework.web.filter.DelegatingFilterProxy
    </filter-class>
</filter>
<filter-mapping>
    <filter-name>shiroFilter</filter-name>
    <url-pattern/ * < / >url-pattern>
</filter-mapping>
Copy the code

DelegatingFilterProxy here USES a proxy filter, because the real shiroFilter need to inject a lot of complex objects, and the web. Only configuration in XML string or a number of parameters, can’t meet, Therefore, we will leave the shiroFilter to Spring to manage and configure through Spring’s XML file. After the DelegatingFilterProxy filter is used, the DelegatingFilterProxy filter automatically finds the beans with the same name as the filter-name configured in the Spring container after the browser sends the request and the request is intercepted by the proxy filter.

3.6.3 create shiro.xml


      
<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <! -- custom Realm-->
  <bean id="myRealm" class="cn.linstudy.shiro.CarBusinessRealm"/>
    <! -- Create a security manager -->
  <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
    <property name="realm" ref="myRealm"/>
  </bean>
  <bean id="shiroFilter"
    class="org.apache.shiro.spring.web.ShiroFilterFactoryBean">
    <! -- Reference the specified security manager -->
    <property name="securityManager" ref="securityManager"/>
    <! -- Shiro's default login address is /login.jsp. Now specify our own login page address -->
    <property name="loginUrl" value="/login.html"/>
    <! -- Path rule -->
    <property name="filterChainDefinitions">
      <! -- Configure the request interception mode, can be anonymous or -->
      <value>
        /empLogin=anon
        /static/**=anon
        /upload/**=anon
        /getImage=anon
        /getEmailCode=anon
        /checkEmail=anon
        /checkUsername=anon
        /error=anon
        /fronted/**=anon
        /**=authc
      </value>
    </property>
  </bean>
</beans>
Copy the code

3.6.4. Import shrio.xml

Introduce Shiro.xml in MVC.xml

<import resource="classpath:shiro.xml"/>
Copy the code

3.6.5. Configure security Manager

We need to configure the security manager in Shiro.xml.

<bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager"></bean>
Copy the code

3.6.6 configuring custom realms

public class CarBusinessRealm extends AuthorizingRealm {  
@Autowired
  private EmployeeService employeeService;

  / / certification
  @Override
  protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token)
      throws AuthenticationException {
    // Obtain the username from the token (when the user logs in)
    String username = (String) token.getPrincipal();
    // Check whether the database exists
    Employee employee = employeeService.selectByUsername(username);
    if(employee ! =null) {
      // If the user name is correct, return an identity object
      return new SimpleAuthenticationInfo(employee, employee.getPassword(), this.getName());
    }
    return null; }}Copy the code

3.6.7 configuring custom realms

<bean id="myRealm" class="cn.linstudy.shiro.CarBusinessRealm"/>
  <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager">
    <property name="realm" ref="myRealm"/>
  </bean>	
Copy the code

3.6.8. Changing the Login Method

      try {
        UsernamePasswordToken token = new UsernamePasswordToken(username, password);
        SecurityUtils.getSubject().login(token);
        Employee employee = employeeMapper.selectByUsername(username);
        return employee;
      } catch (UnknownAccountException e) {
        throw new CarBussinessException("Incorrect user name");
      } catch (IncorrectCredentialsException e) {
        throw new CarBussinessException("Password error");
      }
Copy the code

3.7, logout

Shiro has a built-in logout method, so we simply add /logout=logout to shiro’s path rule in shiro. XML.