116.Shiro: basic concept of Shiro, basic use of Shiro authentication and authorization

catalogue

1, Basic concept of permission

1. What is permission management

2. What is identity authentication

3. What is authorization

2, Basic knowledge of Shiro

1. What is Shiro

2. Core architecture of Shiro

3, Shrio first program user authentication

1. Basic concepts

(1) Subject: subject

(2) Principal: identity information

(3) Credential: credential information

2. Certification process

3. Example preparation

(1) Create project

(2) Introducing shiro dependency

(3) Import shiro profile

(4) Write control class

(5) Testing

4. Interpretation of authentication source code

5. Instance Optimization: Custom Realm

4, DM5 and Salt

1.MD5 algorithm

(1) Characteristics

(2) Function

(3) Generate results

2.Salt

3.md5+salt+hash hash instance

5, Authentication in Shiro: implementation of MD5+Salt+Hash

1. Query the ciphertext corresponding to the password

2. Implementation of MD5+Salt+Hash in Shiro

6, Authorization in Shiro

1. Basic concepts

2. Authorization method

3. Permission string

4. Programming implementation of authorization

5. Authorized instance code

7, Reward request

1, Basic concept of permission

1. What is permission management

Permission management belongs to the category of system security. Permission management realizes the control of users' access to the system and controls that users can and can only access their authorized resources according to security rules.

Authority management includes identity authentication and authorization.

 

2. What is identity authentication

The process of judging whether a user is a legal user.

The most common methods are user name and password, fingerprints, face brushing and so on.

 

3. What is authorization

Authorization, or access control, controls who can access which resources.

 

2, Basic knowledge of Shiro

1. What is Shiro

Official website address: http://shiro.apache.org/

 

Shiro is an open source framework under Apache. It extracts the functions related to security authentication of software system, realizes user identity authentication, authority authorization, encryption, session management and other functions, and forms a general security authentication framework.

 

2. Core architecture of Shiro

 

3, Shrio first program user authentication

1. Basic concepts

(1) Subject: subject

Users accessing the system are authenticated by the main body

(2) Principal: identity information

It is the identification of the subject for identity authentication and has uniqueness. A subject can have multiple identities, but it must have one primary identity

(3) Credential: credential information

Only the subject knows the security information

 

2. Certification process

The subject generates additional information through identity information and voucher information, and then verifies whether the token is legal.

 

3. Example preparation

(1) Create project

After creation, maven will be automatically introduced, and then two new resources folders will be added:

(2) Introducing shiro dependency

(3) Import shiro profile

Note that shiro is a configuration file ending in ini, not a regular property or yml.

The configuration file only needs to be placed in any directory under resources.

 

We don't notice that ini is used to write the relevant files in this project. It eliminates the operation related to editing the database and simplifies the learning process

 

The above [users] is fixed:

(4) Write control class

package com.xupeng;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.mgt.DefaultSecurityManager;
import org.apache.shiro.realm.text.IniRealm;
import org.apache.shiro.subject.Subject;

public class TestAuthenticator {
    public static void main(String[] args) {
        //1. Create security manager object
        DefaultSecurityManager securityManager = new DefaultSecurityManager();

        //2. Set realm to the Security Manager (realm provides relevant data)
        securityManager.setRealm(new IniRealm("classpath:shiro.ini"));

        //3.SecurityUtils global security tool class
        SecurityUtils.setSecurityManager(securityManager);

        //4. Key object: subject object
        Subject subject = SecurityUtils.getSubject();

        //5. Create token
        UsernamePasswordToken token = new UsernamePasswordToken("xupeng","456");
        try{
            System.out.println("Certification status:"+subject.isAuthenticated());
            subject.login(token);//User login authentication
            System.out.println("Certification status:"+subject.isAuthenticated());
        }catch (UnknownAccountException e){
            e.printStackTrace();
            System.out.println("Authentication failed. The authenticated user does not exist");
        }catch (IncorrectCredentialsException e){
            e.printStackTrace();
            System.out.println("Authentication failed, password error");
        }


    }
}

(5) Testing

We will find that the status has changed, which proves that the login is successful

 

4. Interpretation of authentication source code

(1) The authentication of the final user name is in SimpleAccountRealm:

(2) The verification of password is in the AuthenticatingRealm class:

Once our password is incorrect, it will report an IncorrectCredentialsException exception, and the source code will be clear here

 

5. Instance Optimization: Custom Realm

In the above example, the user name and password are written in the ini file, but in actual use, they must be placed in the database. Let's simulate the database and make a simple example first

 

CustomerRealm:

package com.xupeng.realm;

import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;

/**
 * Customize the implementation of Realm to convert the source of authentication / authorization data into the implementation of database
 */
public class CustomerRealm extends AuthorizingRealm {
    //to grant authorization
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        return null;
    }

    //authentication
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        //Get user name in token
        String principal = (String) authenticationToken.getPrincipal();
        System.out.println(principal);
        //Use jdbc mybatis to query relevant databases according to identity information
        if("xupeng".equals(principal)){
            //Parameter 1: correct user name in database
            //Parameter 2: correct password in database
            //Parameter 3: provide current Realm name
            SimpleAuthenticationInfo simpleAuthenticationInfo  = new SimpleAuthenticationInfo("xupeng","456",this.getName());
            return simpleAuthenticationInfo;
        }
        return null;
    }
}

TestCustomerRealmAuthenticator:

package com.xupeng;

import com.xupeng.realm.CustomerRealm;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.mgt.DefaultSecurityManager;
import org.apache.shiro.subject.Subject;

/**
 * Use custom Realm
 */
public class TestCustomerRealmAuthenticator {
    public static void main(String[] args) {
        //Create SecurityManager
        DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager();
        //Set custom realm
        defaultSecurityManager.setRealm(new CustomerRealm());
        //Set security tool class
        SecurityUtils.setSecurityManager(defaultSecurityManager);
        //Obtain the subject through the security tool class
        Subject subject = SecurityUtils.getSubject();
        //Create token
        UsernamePasswordToken token = new UsernamePasswordToken("xupeng","456");

        try {

            subject.login(token);
            System.out.println(subject.isAuthenticated());
        }catch (UnknownAccountException e){
            e.printStackTrace();
            System.out.println("Authentication failed. The authenticated user does not exist");
        }catch (IncorrectCredentialsException e){
            e.printStackTrace();
            System.out.println("Authentication failed, password error");
        }
    }
}

Test:

 

4, DM5 and Salt

The database cannot store passwords in clear text. We need MD5 encryption and Salt.

 

1.MD5 algorithm

(1) Characteristics

  • MD5 algorithm is irreversible.
  • If the contents are the same, the results generated by md5 will be the same no matter how many times it is executed

(2) Function

Generally used for encryption or signature.

Signature let's explain here. When we download software, we often see an md5 suffix file on the official website, which is used to verify whether the software you download is missing. After md5 encryption, the downloaded file should be the same as the file with md5 suffix provided on the official website.

(3) Generate results

The result generated by md5 is always a hexadecimal 32-bit string

 

2.Salt

(1) MD5 algorithm problem
Now there are exhaustive websites on the Internet. If we directly save MD5 with our password, it's easier to compare with exhaustive websites with MD5. So we add some of our own things to the password, which is called salt. Increase the complexity of comparison and ensure the relative security of passwords.

 

3.md5+salt+hash hash instance

 

5, Authentication in Shiro: implementation of MD5+Salt+Hash

1. Query the ciphertext corresponding to the password

TestShiroMD5
package com.xupeng;

import org.apache.shiro.crypto.hash.Md5Hash;

public class TestShiroMD5 {
    public static void main(String[] args) {
        //Direct use of md5 algorithm
        Md5Hash md5Hash = new Md5Hash("456");
        System.out.println(md5Hash.toHex());

        //Using md5+salt
        Md5Hash md5Hash1 = new Md5Hash("456","xp");
        System.out.println(md5Hash1.toHex());

        //Use md5+salt+hash hash
        //Where 1024 indicates 1024 hashes of salt addition results
        Md5Hash md5Hash2 = new Md5Hash("456","xp",1024);
        System.out.println(md5Hash2.toHex());
    }
}

2. Implementation of MD5+Salt+Hash in Shiro

CustomerMd5Realm:

package com.xupeng.realm;

import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;

/**
 * Customize the implementation of Realm and add md5+salt+hash hash
 */
public class CustomerMd5Realm extends AuthorizingRealm {
    //to grant authorization
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        return null;
    }

    //authentication
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        //Get user name in token
        String principal = (String) authenticationToken.getPrincipal();
        System.out.println(principal);
        //Use jdbc mybatis to query relevant databases according to identity information
        if("xupeng".equals(principal)){
            //Parameter 1: correct user name in database
            //Parameter 2: correct MD5 password in database
            //Parameter 3: provide current Realm name
//            SimpleAuthenticationInfo simpleAuthenticationInfo  = new SimpleAuthenticationInfo(
//                    "xupeng",
//                    "250cf8b51c773f3f8dc8b4be867a9a02",
//                    this.getName());

            //Parameter 1: correct user name in database
            //Parameter 2: correct MD5 password + salt password in the database. If the number of hashes is added, the password after hashing is set
            //Parameter 3: random salt at registration
            //Parameter 4: provide current Realm name
            SimpleAuthenticationInfo simpleAuthenticationInfo  = new SimpleAuthenticationInfo(
                    "xupeng",
                    "4ca532fb479910d125d72992a3f57b33",
                    ByteSource.Util.bytes("xp"),
                    this.getName());
            return simpleAuthenticationInfo;
        }
        return null;
    }
}

TestCustomerMd5RealmAuthenticator:

package com.xupeng;

import com.xupeng.realm.CustomerMd5Realm;
import com.xupeng.realm.CustomerRealm;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.mgt.DefaultSecurityManager;
import org.apache.shiro.subject.Subject;

/**
 * Use custom Realm and add md5+salt+hash hash
 */
public class TestCustomerMd5RealmAuthenticator {
    public static void main(String[] args) {
        //Create SecurityManager
        DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager();
        //Inject Realm
        CustomerMd5Realm customerMd5Realm = new CustomerMd5Realm();
        //Set realm to use hash credential matcher
        HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher();
        credentialsMatcher.setHashAlgorithmName("md5");
        credentialsMatcher.setHashIterations(1024);
        customerMd5Realm.setCredentialsMatcher(credentialsMatcher);
        defaultSecurityManager.setRealm(customerMd5Realm);
        //Set security tool class
        SecurityUtils.setSecurityManager(defaultSecurityManager);
        //Obtain the subject through the security tool class
        Subject subject = SecurityUtils.getSubject();
        //Create token
        UsernamePasswordToken token = new UsernamePasswordToken("xupeng","456");

        try {

            subject.login(token);
            System.out.println(subject.isAuthenticated());
        }catch (UnknownAccountException e){
            e.printStackTrace();
            System.out.println("Authentication failed. The authenticated user does not exist");
        }catch (IncorrectCredentialsException e){
            e.printStackTrace();
            System.out.println("Authentication failed, password error");
        }
    }
}

 

6, Authorization in Shiro

Authorization, or access control, controls who can access which resources.

1. Basic concepts

(1) Host: Subject

(2) Resource: Resource

(3) Permission: permission

 

2. Authorization method

  • Role based access control
  • Resource based access control

 

3. Permission string

For resource-based access control, the rule of permission string is:

Resource identifier: Action: resource instance identifier

It means what operations are performed on which instance of that resource

 

example:

User creation permission:

user:create, or user:create:*

User's permission to modify instance 001:

user:update:001

All permissions of user instance 001:

user:*:001

 

4. Programming implementation of authorization

(1) Programming

(2) Annotation type

(3) Label type

 

5. Authorized instance code

The premise of authorization is to pass the authentication. Let's take the example of MD5 + salt + hash above to operate:

CustomerMd5Realm:

The doGetAuthorizationInfo method is used for authorization

package com.xupeng.realm;

import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;

/**
 * Customize the implementation of Realm and add md5+salt+hash hash
 */
public class CustomerMd5Realm extends AuthorizingRealm {
    //to grant authorization
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        System.out.println("------------------------");
        String principal = (String) principalCollection.getPrimaryPrincipal();
        System.out.println("Identity information:"+principal);

        //Obtain the role information and permission information of the current user according to the identity information and user name
        SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
        simpleAuthorizationInfo.addRole("admin");
        simpleAuthorizationInfo.addRole("user");

        //Copy the query permission information in the database to the permission object
        simpleAuthorizationInfo.addStringPermission("user:*:01");
        simpleAuthorizationInfo.addStringPermission("product:create");

        return simpleAuthorizationInfo;
    }

    //authentication
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        //Get user name in token
        String principal = (String) authenticationToken.getPrincipal();
        System.out.println(principal);
        //Use jdbc mybatis to query relevant databases according to identity information
        if("xupeng".equals(principal)){
            //Parameter 1: correct user name in database
            //Parameter 2: correct MD5 password in database
            //Parameter 3: provide current Realm name
//            SimpleAuthenticationInfo simpleAuthenticationInfo  = new SimpleAuthenticationInfo(
//                    "xupeng",
//                    "250cf8b51c773f3f8dc8b4be867a9a02",
//                    this.getName());

            //Parameter 1: correct user name in database
            //Parameter 2: correct MD5 password + salt password in the database. If the number of hashes is added, the password after hashing is set
            //Parameter 3: random salt at registration
            //Parameter 4: provide current Realm name
            SimpleAuthenticationInfo simpleAuthenticationInfo  = new SimpleAuthenticationInfo(
                    "xupeng",
                    "4ca532fb479910d125d72992a3f57b33",
                    ByteSource.Util.bytes("xp"),
                    this.getName());
            return simpleAuthenticationInfo;
        }
        return null;
    }
}

TestCustomerMd5RealmAuthenticator

package com.xupeng;

import com.xupeng.realm.CustomerMd5Realm;
import com.xupeng.realm.CustomerRealm;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.mgt.DefaultSecurityManager;
import org.apache.shiro.subject.Subject;

import java.util.Arrays;

/**
 * Use custom Realm and add md5+salt+hash hash
 */
public class TestCustomerMd5RealmAuthenticator {
    public static void main(String[] args) {
        //Create SecurityManager
        DefaultSecurityManager defaultSecurityManager = new DefaultSecurityManager();
        //Inject Realm
        CustomerMd5Realm customerMd5Realm = new CustomerMd5Realm();
        //Set realm to use hash credential matcher
        HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher();
        credentialsMatcher.setHashAlgorithmName("md5");
        credentialsMatcher.setHashIterations(1024);
        customerMd5Realm.setCredentialsMatcher(credentialsMatcher);
        defaultSecurityManager.setRealm(customerMd5Realm);
        //Set security tool class
        SecurityUtils.setSecurityManager(defaultSecurityManager);
        //Obtain the subject through the security tool class
        Subject subject = SecurityUtils.getSubject();
        //Create token
        UsernamePasswordToken token = new UsernamePasswordToken("xupeng","456");

        try {

            subject.login(token);
            System.out.println(subject.isAuthenticated());
        }catch (UnknownAccountException e){
            e.printStackTrace();
            System.out.println("Authentication failed. The authenticated user does not exist");
        }catch (IncorrectCredentialsException e){
            e.printStackTrace();
            System.out.println("Authentication failed, password error");
        }

        //Authenticate users for authorization
        if(subject.isAuthenticated()){
            //1. Role based permission control
            System.out.println(subject.hasRole("admin"));

            //2. Multi role based permission control
            System.out.println(subject.hasRoles(Arrays.asList("admin","user")));

            //3. Do you have one of these roles
            boolean[] booleans = subject.hasRoles(Arrays.asList("admin","super","user"));
            for(boolean b:booleans){
                System.out.println(b);
            }

            System.out.println("================================");
            //Access control resource identifier based on permission string: Action: resource instance identifier
            System.out.println("resources:"+subject.isPermitted("user:update:01"));
            System.out.println("resources:"+subject.isPermitted("product:create:02"));

            //What permissions do you have
            boolean[] permitted = subject.isPermitted("user:*:01","order:*:10");
            for(boolean b:permitted){
                System.out.println(b);
            }

            //What permissions do you have at the same time
            boolean permitAll = subject.isPermittedAll("user:*:01","product:create");
            System.out.println(permitAll);

        }
    }
}

 

7, Reward request

If this blog is helpful to you, please give me a reward. Thank you~

 

 

Keywords: Shiro

Added by justinjkiss on Mon, 07 Feb 2022 23:07:33 +0200