Shiro Tutorial (1): Getting Started Overview and Basic Use

Shiro

Chapter 1: Getting Started Overview

1.1 What is Shiro

Apache.Shiro is a powerful and easy-to-use Java security (permissions) framework. Shiro can complete: authentication, authorization, encryption, session management, integration with the Web, caching, etc. Protect any application quickly and easily with Shiro - from the smallest mobile app to the largest web and enterprise applications.

https://shiro.apache.org/

[External link image transfer failed. The source site may have an anti-leeching mechanism. It is recommended to save the image and upload it directly (img-jK1uuMJQ-1689075634369) (C:/Users/Administrator/AppData/Roaming/Typora/typora-user-images/ image-20221014103320768.png)]

1.2 Why use Shiro

The framework landscape has changed considerably since 2003, so there are still many systems using Shiro today. This is inseparable from Shiro's characteristics.

易于使用: Building a system security framework using Shiro is easy. Even if it is your first contact, you can quickly master it.

全面: Shiro contains the functions required by the complete framework of the system and is a one-stop service that meets security needs.

灵活:Shiro can work in any application environment. Although it can work in Web, EJB and IoC environments, it is not required 依赖它们. Shiro also doesn't enforce any specifications or even many dependencies.

强力支持Web: Shiro has excellent web application support, allowing the creation of flexible security policies based on application URLs and web protocols such as REST, while also providing a set of JSP libraries to control page output.

兼容性强:Shiro's design patterns make it easy to integrate with other frameworks and applications. Shiro integrates seamlessly with frameworks such as Spring, Grails, Wicket, Tapestry, Mule, Apache Camel, Vaadin, etc.

社区支持: Shiro is an open source project of the Apache Software Foundation, with complete community support and documentation support. Commercial companies like Katasoft also provide professional support and services if needed.

1.3 Comparison between Shiro and SpringSecurity

  1. SpringSecurity is developed based on Spring. If the project uses Spring as the foundation, it will be more convenient to cooperate with SpringSecurity to set permissions. However, Shiro needs to be integrated with Spring for development;
  2. SpringSecurity has richer functions than Shiro, such as security maintenance;
  3. SpringSecurity community resources are relatively richer than Shiro;
  4. Shiro is relatively simple to configure and use, but SpringSecurity is more complicated to get started with;
  5. Shiro has low dependencies, does not require any frameworks and containers, and can run independently. SpringSecurity relies on the Spring container;
  6. Shiro doesn't just work on the Web, it can work in any application environment. Perhaps one of the most important benefits of Shiro when it comes to clustering sessions is that its sessions are container independent.

1.4 Basic functions

  • 认证登录
  • 授权、权限验证
  • 会话管理
  • 加密功能
  • ···

Chapter 2: Basic use

2.1 Environment preparation

1. Shiro does not rely on containers, mavenjust create the project directly.

Create maven project

[External link image transfer failed. The source site may have an anti-leeching mechanism. It is recommended to save the image and upload it directly (img-35seCd2A-1689075634370) (C:/Users/Administrator/AppData/Roaming/Typora/typora-user-images/ image-20221014105855921.png)]

Add module

[External link image transfer failed. The source site may have an anti-leeching mechanism. It is recommended to save the image and upload it directly (img-3eETQRQt-1689075634370) (C:/Users/Administrator/AppData/Roaming/Typora/typora-user-images/ image-20221014105944954.png)]

2. Add dependencies

    <dependencies>
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-core</artifactId>
            <version>1.9.0</version>
        </dependency>

        <dependency>
            <groupId>commons-logging</groupId>
            <artifactId>commons-logging</artifactId>
            <version>1.2</version>
        </dependency>
    </dependencies>

2.2 INI file

Information related to permissions obtained by Shiro can be obtained through the database or through the ini configuration file.

1. Create inifiles

src/main/resources/Create shiro.ini file under

[users]
zhangsan=z3
lisi=l4

2.3 Login authentication

1. Login authentication concept

  • Identity verification: Generally, it is necessary to provide some identifying information such as ID to indicate the identity of the login, such as providing email, username, password, etc.
  • In Shiro, users need to provide principals (identity) and credentials (proof) to Shiro so that the application can verify the user's identity.
  • Principals: Identity, that is, the identification attribute of the principal, which can be any attribute, such as user name, password, and email address, as long as it is unique. A principal can have multiple principals, but there is only one Primary principal. Usually it is user name, email address, and mobile phone number.
  • Credentials: Proof, that is, security values ​​known only to the subject, such as passwords, digital certificates, etc.
  • The most common combination of principals and credentials is username and password.

2. Basic login authentication process

  1. Collect user identities/credentials i.e. username/password.
  2. Call Subject.loginto log in. If it fails, you will get the corresponding AuthenticationException exception and prompt the user with an error message according to the exception; otherwise, the login is successful.
  3. Create custom Realm classes, inherit org.apache.shiro.realm.AuthenticatingRealmclasses, and implement doGetAuthenticationInfo()methods.

3. Login authentication example

Create a package com/wang/shirotest, and then create a new ShiroRun test class under the package

package com.wang.shirotest;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.config.IniSecurityManagerFactory;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.subject.Subject;


public class ShiroRun {
    
    
    public static void main(String[] args) {
    
    
        // 1 初始化获取SecurityManager
        IniSecurityManagerFactory factory = new IniSecurityManagerFactory("classpath:shiro.ini");
        SecurityManager securityManager = factory.getInstance();
        SecurityUtils.setSecurityManager(securityManager);
        // 2 获取Subject对象
        Subject subject = SecurityUtils.getSubject();
        // 3 创建token对象,web应用用户名密码从页面传递
        AuthenticationToken token = new UsernamePasswordToken("zhangsan", "z3");
        // 4 完成登录
        try {
    
    
            subject.login(token);
            System.out.println("登录成功");
        } catch (UnknownAccountException e) {
    
    
            e.printStackTrace();
            System.out.println("用户不存在");
        } catch (IncorrectCredentialsException e) {
    
    
            e.printStackTrace();
            System.out.println("密码错误");
        } catch (AuthenticationException e) {
    
    
            e.printStackTrace();
        }
    }
}

① Login successful
[External link image transfer failed. The source site may have an anti-leeching mechanism. It is recommended to save the image and upload it directly (img-eZwehhkB-1689075634370) (C:/Users/Administrator/AppData/Roaming/Typora/typora-user-images/ image-20221015073506335.png)]
② User does not exist
[External link image transfer failed. The source site may have an anti-leeching mechanism. It is recommended to save the image and upload it directly (img-64kTy3JU-1689075634371) (C:/Users/Administrator/AppData/Roaming/Typora/typora-user-images/ image-20221015073544075.png)]
③ Password incorrect
[External link image transfer failed. The source site may have an anti-leeching mechanism. It is recommended to save the image and upload it directly (img-s3GNJonm-1689075634371) (C:/Users/Administrator/AppData/Roaming/Typora/typora-user-images/ image-20221015073609125.png)]

2.4 Roles and authorization

1. Authorization concept

  • Authorization: also calledAccess control, that is, controlling who has access to which resources in the application. There are several key objects that need to be understood in authorization: Subject, Resource, Permission, and Role.
  • Subject: User who accesses the application, used in ShiroSubjectOn behalf of the user, the user can access the corresponding resources only if authorized.
  • Resources:URLs that users can access in the application, such as viewing/editing certain data. Users can only access after authorization.
  • Permission: The atomic authorization unit in the security policy. Through permissions, we can indicate whether the user has the authority to operate a certain resource in the application.That is, permissions indicate whether the user can access a certain resource in the application.
  • Shiro supports coarse-grained permissions (such as all permissions of the user module) and fine-grained permissions (permissions to operate a certain user, that is, instance level)
  • Role:collection of permissions, in general, users will be given roles instead of permissions, that is, users can have a set of permissions, which is more convenient when granting permissions. Typical examples include: project manager, technical director, and development engineer.

2. Authorization method

  • Programmatically: Completed by writing if/else authorization code

    • if(subject.hasRole('admin')){
              
              
          // 有权限
      } else {
              
              
          // 无权限
      }
      
  • Annotation type: This is completed by placing corresponding annotations on the executed Java method. If there is no permission, the corresponding exception will be thrown.

    • @RequiresRoles("admin")
      public void hello(){
              
              
          // 有权限
      }
      
  • JSP/GSP tag: Completed through the corresponding tag on the JSP/GSP page.

    • <shiro:hasRole name="admin">
      	<!--有权限-->
      </shiro:hasRole>
      

3. Authorization process

  1. First call Subject.isPermitted*/hasRole*the interface, it will delegate to SecurityManager, and SecurityManagerthen it will delegate to Authorizer;
  2. Authorizer is the real authorizer. If called isPermitted(“user:view”), it will first PermissionResolverconvert the string into the corresponding Permissioninstance;
  3. Before authorization, it will call the corresponding function Realmto obtain Subjectthe corresponding roles/permissions to match the incoming roles/permissions;
  4. AuthorizerIt will be judged Realmwhether the role/permission matches the incoming one. If there are multiple Realms, it will be delegated to a ModularRealmAuthorizerloop judgment. If it matches , isPermitted*/hasRole*it will be returned true. Otherwise, it will return to falseindicate authorization failure .

4. Authorization instance

(1) Role judgment

Modify .inithe file and add roles to the user

[users]
zhangsan=z3, role1, role2
lisi=l4

Add code to determine whether the user has this role

try {
    
    
            subject.login(token);
            System.out.println("登录成功");
            // 5 判断角色
            boolean hasRole = subject.hasRole("role1");
            System.out.println("是否拥有此角色:" + hasRole);
        }

run code

[External link image transfer failed. The source site may have an anti-leeching mechanism. It is recommended to save the image and upload it directly (img-RQFCU1GU-1689075634371) (C:/Users/Administrator/AppData/Roaming/Typora/typora-user-images/ image-20221015080206906.png)]

(2) Determine permission information

.iniAdd role permission information to files

[roles]
role1=user:insert,user:select

Add the following code to try

 // 6 判断权限
            boolean hasPermit = subject.isPermitted("user:insert");
            System.out.println("是否拥有此权限:" + hasPermit);

run code

[External link image transfer failed. The source site may have an anti-leeching mechanism. It is recommended to save the image and upload it directly (img-CemusGYD-1689075634372) (C:/Users/Administrator/AppData/Roaming/Typora/typora-user-images/ image-20221015080716940.png)]

You can also use checkPermission()the method to check whether the user has a certain permission

// 也可以用checkPermission方法,但没有返回值,没有权限直接抛异常
subject.checkPermission("user:insert111");

[External link image transfer failed. The source site may have an anti-leeching mechanism. It is recommended to save the image and upload it directly (img-wXeVgYjJ-1689075634372) (C:/Users/Administrator/AppData/Roaming/Typora/typora-user-images/ image-20221015081031095.png)]

5. Complete code

package com.wang.shirotest;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.config.IniSecurityManagerFactory;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.subject.Subject;


public class ShiroRun {
    
    
    public static void main(String[] args) {
    
    
        // 1 初始化获取SecurityManager
        IniSecurityManagerFactory factory = new IniSecurityManagerFactory("classpath:shiro.ini");
        SecurityManager securityManager = factory.getInstance();
        SecurityUtils.setSecurityManager(securityManager);
        // 2 获取Subject对象
        Subject subject = SecurityUtils.getSubject();
        // 3 创建token对象,web应用用户名密码从页面传递
        AuthenticationToken token = new UsernamePasswordToken("zhangsan", "z3");
        // 4 完成登录
        try {
    
    
            subject.login(token);
            System.out.println("登录成功");
            // 5 判断角色
            boolean hasRole = subject.hasRole("role1");
            System.out.println("是否拥有此角色:" + hasRole);
            // 6 判断权限
            boolean hasPermit = subject.isPermitted("user:insert");
            System.out.println("是否拥有此权限:" + hasPermit);
            // 也可以用checkPermission方法,但没有返回值,没有权限直接抛异常
            subject.checkPermission("user:insert111");
        } catch (UnknownAccountException e) {
    
    
            e.printStackTrace();
            System.out.println("用户不存在");
        } catch (IncorrectCredentialsException e) {
    
    
            e.printStackTrace();
            System.out.println("密码错误");
        } catch (AuthenticationException e) {
    
    
            e.printStackTrace();
        }
    }
}

2.5 Shiro encryption

In actual system development, some sensitive information needs to be encrypted, such as user passwords. Shiro has many commonly used encryption algorithms built-in, such as MD5 encryption. Shiro makes it easy to use message encryption.

1. Use Shiro for password encryption

Can use normal encryption and encryption with salt

package com.wang.shirotest;


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

public class ShiroMD5 {
    
    
    public static void main(String[] args) {
    
    
        // 密码明文
        String password = "z3";
        // 使用MD5加密
        Md5Hash md5Hash = new Md5Hash(password);
        System.out.println("MD5加密后的密码=" + md5Hash);
        // 带盐的MD5加密,盐就是在密码明文后拼接新字符串,然后在进行加密
        Md5Hash md5Hash1 = new Md5Hash(password, "salt");
        System.out.println("带盐的MD5加密后的密码=" + md5Hash1);
    }
}

Print the encrypted password

[External link image transfer failed. The source site may have an anti-leeching mechanism. It is recommended to save the image and upload it directly (img-wd8oewkE-1689075634372) (C:/Users/Administrator/AppData/Roaming/Typora/typora-user-images/ image-20221015083057323.png)]

2. Multiple encryption

Md5Hash md5Hash2 = new Md5Hash(password, "salt", 3);
System.out.println("带盐的MD5的3次加密后的密码=" + md5Hash2);

Encrypted passwords are more difficult to crack

带盐的MD5的3次加密后的密码=7174f64b13022acd3c56e2781e098a5f

Use parent class for encryption

 // 使用父类进行加密
        SimpleHash simpleHash = new SimpleHash("MD5", password, "salt", 3);
        System.out.println("父类的带盐的MD5的3次加密后的密码=" + simpleHash.toHex());

As you can see from the printing results, the password after encrypting it twice and three times with the same salt is the same.

[External link image transfer failed. The source site may have an anti-leeching mechanism. It is recommended to save the image and upload it directly (img-vp3qdaP9-1689075634373) (C:/Users/Administrator/AppData/Roaming/Typora/typora-user-images/ image-20221016072615161.png)]

2.6 Shiro custom login authentication

Shiro's default login authentication is without encryption . If you want to implement encrypted authentication, you need to customize login authentication and customize Realm.

1. Certification implementation

package com.wang.shirotest;

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.realm.AuthenticatingRealm;
import org.apache.shiro.util.ByteSource;


/**
 * @author Administrator
 */
public class MyRealm extends AuthenticatingRealm {
    
    

    // 自定义登录认证方法,Shiro的login方法底层会调用该类的认证方法进行认证
    // 需要配置自定义的Realm生效,在ini文件中可以配置
    // 该方法只是获取进行对比的信息,认证逻辑还是按照Shiro底层认证逻辑完成

    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
    
    

        // 1、获取身份信息
        String principal = authenticationToken.getPrincipal().toString();
        System.out.println("认证用户信息 = " + principal);
        // 2、获取凭证信息
        String password = new String((char[])authenticationToken.getCredentials());
        System.out.println("密码 = " + password);
        // 3、访问数据库获取用户信息
        if(principal.equals("zhangsan")){
    
    
            // 3.1、数据库中存的是加盐迭代3次之后的密码
            String passwordInfo = "7174f64b13022acd3c56e2781e098a5f";
            // 4、创建封装校验逻辑的对象,封装数据返回
            AuthenticationInfo info = new SimpleAuthenticationInfo(
                    authenticationToken.getPrincipal(),
                    passwordInfo,
                    ByteSource.Util.bytes("salt"),
                    authenticationToken.getPrincipal().toString()
            );
            return info;
        }

        return null;
    }
}

2. Add configuration information in Shiro.ini

[main]
md5CredentialsMatcher=org.apache.shiro.authc.credential.Md5CredentialsMatcher
md5CredentialsMatcher.hashIterations=3

myrealm=com.wang.shirotest.MyRealm
myrealm.credentialsMatcher=$md5CredentialsMatcher
securityManager.realms=$myrealm

Guess you like

Origin blog.csdn.net/WwLK123/article/details/131667843