Introduction and use of Shiro

Introduction to Shiro (nonsense)

Apache Shiro is a functional 强大且易于使用Java security (permission) framework. Shiro can complete: authentication, authorization, encryption, session management, integration with the Web, caching, etc. With Shiro you can quickly and easily secure any application—from the smallest mobile app to the largest web and enterprise application.

1: Why use shiro

The framework landscape has changed considerably since 2003, so there are still many systems using Shiro today. This is inseparable from the characteristics of Shiro.
Ease of use : Building a system security framework with Shiro is very simple. Even the first contact can be quickly mastered.
Comprehensive : Shiro includes the functions required by the system security framework and is a "one-stop service" that meets security requirements. Flexible: Shiro can work in any application environment. While it works in ·Web, EJB· and ·IOC·environments, there is no need to depend on them. Shiro also doesn't enforce any specifications, and doesn't even have many dependencies.
Strong support for the Web : Shiro has excellent Web application support, can create flexible security policies based on application URLs and Web protocols (such as REST), and also provides a set of JSP libraries to control page output .
Strong Compatibility : Shiro's design patterns make it easy to integrate with other frameworks and applications. Shiro seamlessly integrates with Spring, Grails, Wicket, Tapestry, Mule, Apache Camel, Vaadin and other frameworks.

2 Comparison between Shiro and Spring Security

1. Spring Security is developed based on Spring. If the project uses Spring as the foundation, it is more convenient to cooperate with Spring Security to do permissions, while Shiro needs to be integrated with Spring; 2. Spring Security has more functions than
Shiro , such as security maintenance; e
3. Spring Security community resources are more abundant than Shiro;
4. The configuration and use of Shiro are relatively simple, while Spring Security is more complicated to get started; 5.
Shiro has low dependency, It does not require any framework and container, and can run independently. Spring Security relies on the Spring container; "
6. Shiro can not only be used in the web, but it can work in any application environment. Perhaps one of the most important benefits of Shiro when clustering sessions
is that its sessions are container-independent.

insert image description here

  • Authentication: identity authentication/login, to verify whether the user has the corresponding identity;
  • Authorization: Authorization, that is, authority verification, verifies whether an authenticated user has a certain authority; that is, judges whether a user can do things, such as: verifying whether a user has a certain role. Or fine-grained verification of whether a user has a certain permission to a certain resource;
  • Session Management: session management, that is, a session after the user logs in, and all its information is in the session before logging out; the session can be in a normal JavaSE environment or in a web environment;
  • Cryptography: Encryption to protect the security of data, such as encrypted storage of passwords to the database instead of plaintext storage;
  • Web Support: Web support, can be easily integrated into the Web environment;
  • Caching: Caching, for example, after a user logs in, his user information, roles/permissions do not need to be checked every time, which can improve efficiency;
  • Concurrency: Shiro supports concurrent verification of multi-threaded applications, that is, if another thread is started in one thread, the permissions can be automatically propagated;
  • Testing: provide testing support;
  • Run As: Allows a user to pretend to be another user (if they allow it);
  • Remember Me: Remember me, this is a very common function, that is, after logging in once, you don't need to log in next time.
    Remember, Shiro will not maintain users and permissions; these need to be designed/provided by ourselves; and then injected into Shiro through the corresponding interface.

insert image description here
It can be seen that the object directly interacted with by the application code is the Subject, which means that the core of Shiro's external API is the Subject; the meaning of each API:

Subject: The subject represents the current "user". This user is not necessarily a specific person. Anything that interacts with the current application is a Subject, such as web crawlers, robots, etc.; that is, an abstract concept; all Subjects are bound to SecurityManager, all interactions with Subject will be delegated to SecurityManager; Subject can be considered as a facade; SecurityManager is the actual executor;

SecurityManager: Security Manager; that is, all security-related operations will interact with SecurityManager; and it manages all Subjects; it can be seen that it is the core of Shiro, which is responsible for interacting with other components introduced later. If you have learned SpringMVC, You can think of it as the DispatcherServlet front controller;

Realm: Domain, Shiro obtains security data (such as users, roles, and permissions) from Realm, that is to say, SecurityManager needs to obtain the corresponding user from Realm to compare to determine whether the user's identity is legal; it also needs to obtain from Realm The user's corresponding role/authority is used to verify whether the user can perform operations; Realm can be regarded as a DataSource, that is, a secure data source.

That is to say, for us, the simplest Shiro application:

The application code is authenticated and authorized through the Subject, and the Subject is delegated to the SecurityManager;

We need to inject Realm into Shiro's SecurityManager, so that SecurityManager can get legal users and their permissions to judge.
It can also be seen from the above that Shiro does not provide maintenance users/permissions, but allows developers to inject themselves through Realm.

Next, let's look at Shiro's architecture from inside Shiro, as shown in the following figure:
insert image description here

  • Subject : the subject, you can see that the subject can be any "user" who can interact with the application;

  • SecurityManager : Equivalent to DispatcherServlet in SpringMVC or FilterDispatcher in Struts2; it is the heart of Shiro; all specific interactions are controlled by SecurityManager; it manages all Subjects, and is responsible for authentication and authorization, as well as session and cache management.

  • Authenticator : Authenticator, which is responsible for subject authentication. This is an extension point. If users feel that Shiro’s default is not good, they can customize the implementation; it requires an authentication strategy (Authentication Strategy), that is, under what circumstances is the user authentication passed;

  • Authorizer : The authorizer, or access controller, is used to determine whether the subject has permission to perform corresponding operations; that is, it controls which functions the user can access in the application;

  • Realm : There can be one or more Realms, which can be considered as security entity data sources, that is, used to obtain security entities; it can be JDBC implementation, LDAP implementation, or memory implementation, etc.; provided by the user; Note: Shiro doesn't know where and in what format your user/permissions are stored; so we generally need to implement our own Realm in the application;

  • SessionManager : If you have written Servlet, you should know the concept of Session. Session needs someone to manage its life cycle. This component is SessionManager; and Shiro can be used not only in the Web environment, but also in ordinary JavaSE environments, EJB and other environments; therefore, Shiro abstracts its own Session to manage the data interacted between the subject and the application; in this case, for example, when we use it in the Web environment, it was a Web server at first; Server; At this time, I want to put the session data of the two servers in one place. At this time, I can realize my own distributed session (such as putting the data in the Memcached server);

  • SessionDAO : DAO has been used by everyone, data access objects, CRUD for sessions, for example, if we want to save the Session to the database, then we can implement our own SessionDAO, and write to the database through JDBC; for example, if we want to put the Session in Memcached, You can implement your own Memcached SessionDAO; in addition, you can use Cache in SessionDAO to improve performance;

  • CacheManager : cache controller to manage caches such as users, roles, permissions, etc.; because these data are rarely changed, they can improve access performance after being placed in the cache

  • Cryptography : Cipher module, Shiro provides some common encryption components for such as password encryption/decryption.

Basic use of Shiro (use)

Introduce dependencies

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

提供shiro可以获取的相关的信息,一般是通过数据库获取(后续整合spring会记录),也可以通过使用**.ini文件获取

login authentication

(1) Identity verification: Generally, it is necessary to provide some identification information such as identity ID to indicate the identity of the login, such as providing email, user name/password to prove.

(2) In shiro, the user needs to provide principals (identity) and credentials (proof) to shiro, so that the application can verify the user's identity
身份和证明 说白了就是userName 和 passWord

Login authentication steps

  1. Collect user identity/credentials, i.e. username/password
  2. Call Subject.login to log in, if it fails, you will get the corresponding AuthenticationException exception, and prompt the user error message according to the exception; otherwise, the login is successful
  3. Create a custom Realm class and inherit the org.apache.shiro.realm.AuthenticatingRealm class to implement the doGetAuthenticationInfo() method

Authentication code implementation steps

1 Initialize to obtain SecurityManager
2 Obtain Subject object
3 Chuangda token object, web application user name is passed across codes from the page
4 Complete login (no exception means login is successful)
通过抓取不同的异常来获取不同的错误信息

 public static void main(String[] args) {
    
    
        //1初始化获取SecurityManager
        DefaultSecurityManager defaultSecurityManager=new DefaultSecurityManager();
        IniRealm iniRealm = new IniRealm("classpath:shiro.ini");
        defaultSecurityManager.setRealm(iniRealm);
        SecurityUtils.setSecurityManager(defaultSecurityManager);
        //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) {
    
    
            System.out.println("登录失败");
        }
    }

Authentication

concept

Authorization, also called access control, is to control who accesses which resources in the application (such as accessing pages/editing data/page operations, etc.). Several key objects need to be understood in authorization: Subject, Resource, Permission, and Role.

  1. Subject (Subject): The user who accesses the application, and ·Subject· is used in ·Shiro· to represent the user. Users are allowed to access corresponding resources only after authorization.
  2. Resource: URLs that users can access in the application, such as accessing JSP pages, viewing/editing some data, accessing a business method, printing text, etc. are all resources. Users can only access after authorization.
  3. Permission: The atomic authorization unit in the security policy. Through the permission, we can indicate whether the user has the right to operate a certain resource in the application. That is, the permission indicates whether the user can access a certain resource in the application, such as; accessing the user list page to view/add/modify/delete user data (that is, in many cases, it is CRUD (add query, modify and delete) type permission control )wait. Permissions represent whether a user has the right to operate a certain resource, that is, whether the operation on a certain resource is allowed or not.
  4. Shiro 支持粗粒度权限(如用户模块的所有权限)和细粒度权限(操作某个用户的权限,即实例级别的)
  5. Role (Role): A collection of permissions. Generally, users are given roles instead of permissions, that is, users can have a set of permissions, which is more convenient when granting permissions. Typical examples: project manager, technical director, CTO, development engineer, etc. are all roles, and different roles have a different set of permissions

Authorization method

  1. Judging by the subject.hasRole() method
  2. Authorize through the @RequestRole() annotation, if the authorization fails, a corresponding exception will be thrown

Authorization process

  1. First call the Subject.isPermitted / hasRole interface, which will delegate to the SecurityManager, and the SecurityManager will then delegate to the Authorizer;
  2. Authorizer is the real authorizer. If you call isPermitted("user:view"), it will first convert the string into the corresponding Permission instance through PermissionResolver;
  3. Before authorization, it will call the corresponding Realm to obtain the corresponding role/permission of the Subject to match the incoming role/permission
  4. The Authorizer will judge whether the role/permission of the Realm matches the incoming one. If there are multiple Realms, it will be entrusted to the ModularRealmAuthorizer for cyclic judgment. If it matches such as isPermitted*/hasRole*, it will return true, otherwise it will return false to indicate that the authorization failed

Add relevant information in the ini file

[users]
//用户名=密码,角色1,角色2
zhangsan=z3,role1,role2
lisi=l4

[roles]
//角色1=权限1,权限2
role1=user:insert,user::select

Determine whether the user has this role by subject.hasRole ("role")

Determine whether the role has this permission by subject.isPermitted("permission identifier")

Judging permissions can also use subject.checkPermission(),

The difference is that checkPermission() does not return a value and throws an exception if there is no permission

        //1初始化获取SecurityManager
        DefaultSecurityManager defaultSecurityManager=new DefaultSecurityManager();
        IniRealm iniRealm = new IniRealm("classpath:shiro.ini");
        defaultSecurityManager.setRealm(iniRealm);
        SecurityUtils.setSecurityManager(defaultSecurityManager);
        //2获取Subject对像
        Subject subject = SecurityUtils.getSubject();
        //3创达token对象,web应用用户名跨码从页面传递
        AuthenticationToken token = new UsernamePasswordToken("zhangsan","z3");
        // 4完成登录
        try {
    
    
            subject.login(token);
            System.out.println("登录成功");
           // 5判断角色
            System.out.println(subject.hasRole("role1") ? "通过":"不通过");
           // 6判断权限
            System.out.println(subject.isPermitted("user:insert") ? "授权插入" : "无权插入");
        }catch (UnknownAccountException e){
    
    
            e.printStackTrace();
            System.out.println("用户不存在");
        }catch (IncorrectCredentialsException e){
    
    
            e.printStackTrace();
            System.out.println("密码错误");
        } catch (AuthenticationException e) {
    
    
            System.out.println("登录失败");
        }

Shiro use - integrating spring (actual combat)

1. Import related configuration

       <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-spring</artifactId>
            <version>1.9.1</version>
        </dependency>
        	
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-core</artifactId>
            <version>1.9.1</version>
        </dependency>

2. The custom Realm class inherits AuthorizingRealm and overrides the corresponding method

  1. Get user identity information
  2. Call the business layer to obtain user information (database)
  3. Non-empty judgment, encapsulate the data and return
@Component
public class MyRealm extends AuthorizingRealm {
    
    

    @Autowired
    private UserMapper userMapper;


//    授权
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
    
    
        return null;
    }
//  登录
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
    
    
    //1 获取用户身份信息
        String name = authenticationToken.getPrincipal().toString();
	//2 调用业务层获取用户信息 (数据库)
        User user = userMapper.selectById(name);
	//3 非空判断,将数据封装返回
        if (user != null){
    
    
            SimpleAuthenticationInfo sai = new SimpleAuthenticationInfo(
            name, user.getPassword(), ByteSource.Util.bytes("salt"), MyRealm.class.getName()
            );
            return sai;
        }
        return null;
    }
}

3. Write shiro configuration class

Configure securityManager

  1. Create a defaultWebSecurityManager object
  2. Create a spanning object and set related attributes
    2.1 Use md5 encryption
    2.2 Iterative encryption times
  3. Store the plus object in myRealm
  4. Save myRealm as an AdefaultWebSecurityManager object
  5. return

Configure shiro's built-in filter interception range

defaultShiroFilterChainDefinition.addPathDefinition("/path", "difinition")
definition parameter description

defaultShiroFilterChainDefinition.addPathDefinition("/path","difinition")
difinition mean
anon Anyone can access without login
authc Must be logged in to access, does not have the function of remember me
user Only logged-in users can access, with the function of remember me
  1. authentication required
  2. no authentication required
@Configuration
public class shiroConfig {
    
    

    @Autowired
    private MyRealm myRealm;

    @Bean
    public DefaultWebSecurityManager defaultWebSecurityManager() {
    
    
        DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager();
        HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
        hashedCredentialsMatcher.setHashAlgorithmName("md5");
        hashedCredentialsMatcher.setHashIterations(3);
        myRealm.setCredentialsMatcher(hashedCredentialsMatcher);
        defaultWebSecurityManager.setRealm(myRealm);
        ThreadContext.bind(defaultWebSecurityManager);
        return defaultWebSecurityManager;

    }
    //配置shiro内置过滤器拦截范围
    @Bean
    public DefaultShiroFilterChainDefinition shiroFilterChainDefinition(){
    
    
        DefaultShiroFilterChainDefinition defaultShiroFilterChainDefinition = new DefaultShiroFilterChainDefinition();
//        不需要认证
        defaultShiroFilterChainDefinition.addPathDefinition("/login","anon");
        defaultShiroFilterChainDefinition.addPathDefinition("/user","anon");
//        需要认证
        defaultShiroFilterChainDefinition.addPathDefinition("/**","authc");

        return defaultShiroFilterChainDefinition;
    }

}

4. Go back to the business layer and verify the login through the subject.login() method

	 Subject subject = SecurityUtils.getSubject();
        AuthenticationToken token = new UsernamePasswordToken(user.getUsername(),user.getPassword());
        try {
    
    
            subject.login(token);
        }catch (Exception e){
    
    
            e.printStackTrace();
            return ComResult.error("登录失败");
        }
        return ComResult.success("登录成功");

Guess you like

Origin blog.csdn.net/weixin_58286934/article/details/128964773