Basic use of Shiro

Shiro

Apache Shiro is a powerful and easy-to-use Java security framework that performs authentication, authorization, encryption, and session management.

  • Authentication: identity authentication / login to verify whether the user has the corresponding identity;
  • Authorization: authorization, i.e. permission verification, determines whether an authenticated user has certain permissions to access certain resources. General authorization includes role authorization and permission authorization;
  • SessionManager: session management, that is, after a user logs in, it is a session. Before exiting, all its information is in the session; The session can be in an ordinary JavaSE environment or in a web environment. The role of the web environment is the same as that of HttpSession;
  • Cryptography: encryption to protect the security of data. For example, the password is encrypted and stored in the database instead of plaintext;

It has three core components: Subject, SecurityManager and Realms

  • Subject: the current operating user;

  • SecurityManager: it is the core of Shiro framework. It is a typical Facade mode. Shiro manages internal component instances through SecurityManager and provides various services for security management.

  • Realms: realms act as a "bridge" or "connector" between Shiro and application security data. That is, when performing authentication (login) and authorization (access control) authentication on the user, Shiro will find the user and his permission information from the Realm configured by the application.

Official 10 minute entry document: https://shiro.apache.org/10-minute-tutorial.html

The following is the example file in the getting started document:

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.mgt.DefaultSecurityManager;
import org.apache.shiro.realm.text.IniRealm;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.Subject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;


public class Quickstart {

    private static final transient Logger log = LoggerFactory.getLogger(Quickstart.class);


    public static void main(String[] args) {

        DefaultSecurityManager securityManager = new DefaultSecurityManager();
        IniRealm iniRealm = new IniRealm("classpath:shiro.ini");
        securityManager.setRealm(iniRealm);


        SecurityUtils.setSecurityManager(securityManager);

        //In almost all environments, you can get the currently executing user through the following call:
        Subject currentUser = SecurityUtils.getSubject();

        //By providing content to users during their current session with the application, you can get their session: (it doesn't need an HTTP environment!)
        Session session = currentUser.getSession();
        session.setAttribute("someKey", "aValue");
        String value = (String) session.getAttribute("someKey");
        if (value.equals("aValue")) {
            log.info("Retrieved the correct value! [" + value + "]");
        }

        //Perform these checks on known users. The instance above our Subject represents the current user to determine whether we have logged in
        if (!currentUser.isAuthenticated()) {
            UsernamePasswordToken token = new UsernamePasswordToken("lonestarr", "vespa");
            token.setRememberMe(true);
            //If the login attempt fails, all kinds of exceptions will be caught and handled in time
            try {
                currentUser.login(token);
            } catch (UnknownAccountException uae) {
                log.info("There is no user with username of " + token.getPrincipal());
            } catch (IncorrectCredentialsException ice) {
                log.info("Password for account " + token.getPrincipal() + " was incorrect!");
            } catch (LockedAccountException lae) {
                log.info("The account for username " + token.getPrincipal() + " is locked.  " +
                        "Please contact your administrator to unlock it.");
            }

            catch (AuthenticationException ae) {

            }
        }

        //Output logged in user information: (test role)
        log.info("User [" + currentUser.getPrincipal() + "] logged in successfully.");

        //Test whether it has a specific function:
        if (currentUser.hasRole("schwartz")) {
            log.info("May the Schwartz be with you!");
        } else {
            log.info("Hello, mere mortal.");
        }

        //See if they have authority to take action against a certain type of entity: (test input permissions)
        if (currentUser.isPermitted("lightsaber:wield")) {
            log.info("You may use a lightsaber ring.  Use it wisely.");
        } else {
            log.info("Sorry, lightsaber rings are for schwartz masters only.");
        }

        //To see if a user has access to a specific instance of a type:
        if (currentUser.isPermitted("winnebago:drive:eagle5")) {
            log.info("You are permitted to 'drive' the winnebago with license plate (id) 'eagle5'.  " +
                    "Here are the keys - have fun!");
        } else {
            log.info("Sorry, you aren't allowed to drive the 'eagle5' winnebago!");
        }

        //User logoff:
        currentUser.logout();

        System.exit(0);
    }
}

Summary:

---Certification:

1. subject gets the user; SecurityUtils.getSubject();

2. UsernamePasswordToken encapsulates data

3. Login; subject.login(token);

Then make some abnormal judgment in some login.

----Interception: three steps

1. Create a realm object;

2,efaultWebSecurityManager

3,ShiroFilterFactoryBeanï¼› All authorization interception operations are configured here

Import shiro dependencies

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

Configure shiro

An existing UserRealm is required:

package com.vxzx.config;

import com.vxzx.pojo.User;
import com.vxzx.server.UserServer;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
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.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;

public class UserRealm extends AuthorizingRealm {
    @Autowired
    UserServer userServer;

    //to grant authorization
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        System.out.println("The authorized method is executed:====>AuthorizationInfo");
        //The user will be authorized to have certain permissions: SimpleAuthorizationInfo
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        //Let all users have the permission of user:add:
//        info.addStringPermission("user:add");

        //Get the current user and let him automatically identify the permissions in the database:
        Subject subject = SecurityUtils.getSubject();
        //Get User:
        User principal = (User) subject.getPrincipal();
        //Set permissions:
        info.addStringPermission(principal.getPerms());
        return info;
    }

    //authentication
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        System.out.println("Method of performing certification:====>AuthenticationInfo");

        UsernamePasswordToken userToken = (UsernamePasswordToken)authenticationToken;
        //Get user information from the database:
        User user = userServer.query(userToken.getUsername());

        if (user==null){
            return null;
        }
        //Password authentication:
        return new SimpleAuthenticationInfo(user,user.getPwd(),"");
    }
}

ShiroConfig: some intercepting configurations are configured in it

package com.vxzx.config;

import at.pollux.thymeleaf.shiro.dialect.ShiroDialect;
import org.apache.shiro.mgt.DefaultSecurityManager;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import java.util.LinkedHashMap;
import java.util.Map;

@Configuration
public class ShiroConfig {
    //ShiroFilterFactoryBean: Step 3 (based on step 2)
    @Bean
    public ShiroFilterFactoryBean factoryBean(@Qualifier("securityManager")DefaultSecurityManager defaultSecurityManager){
        ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
        //Associate the securityManager in step 2:
            //Set up security manager:
        bean.setSecurityManager(defaultSecurityManager);

        //Add shiro's built-in filter:
        /*
        *   anno : Access without authentication
        *   authc : Authentication is required to access
        *   user :  I have to remember before I can visit
        *   perms :  Have permissions on a resource
        *   roles :  Have access to a role
        * */
        Map<String, String> filters = new LinkedHashMap();
        filters.put("/add","authc");
        filters.put("/update","authc");
        //Authorization: without authorization, or jump to the unauthorized page;
        filters.put("/add","perms[user:add]");
        filters.put("/update","perms[user:update]");

        //Filter request:
        bean.setFilterChainDefinitionMap(filters);

        //Insufficient permission, jump to the special page:
        bean.setUnauthorizedUrl("/unauthorized");

        //Set login request:
        bean.setLoginUrl("/tologin");

        //

        return bean;
    }

    //DefaultWebSecurityManager: Step 2 (based on step 1)
    @Bean(name="securityManager")
    public DefaultWebSecurityManager defaultWebSecurityManager(@Qualifier("user")UserRealm userRealm){
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        //Associate userRealm in step 1:
        securityManager.setRealm(userRealm);
        return securityManager;
    }

    //Creating a realm object: Step 1
    @Bean(name="user")
    public UserRealm userRealm(){
        return  new UserRealm();
    }

    //By integrating ShiroDialect, Shiro Thymeleaf can be integrated
    @Bean
    public ShiroDialect shiroThy(){
        ShiroDialect dialect = new ShiroDialect();
        return dialect;
    }
}

The controller configures the jump of the front page:

package com.vxzx.controller;

import com.vxzx.dao.UserMapper;
import com.vxzx.pojo.User;
import org.apache.ibatis.annotations.Mapper;
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.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

@Controller
public class RouterC {
    @Autowired
    UserMapper userMapper;

    @RequestMapping({"/","index"})
    public String toIndex(Model model){
        model.addAttribute("msg","Hello,Shiro");
        return "index";
    }

    @RequestMapping("/add")
    public String add(){
        return "user/add";
    }

    @RequestMapping("/update")
    public String update(){
        return "user/update";
    }

    @RequestMapping("/tologin")
    public String tologin(){
        return "user/login";
    }

    @RequestMapping("/login")
    public String login(String username,String password,Model model){
        //Get the currently executing user
        Subject subject = SecurityUtils.getSubject();
        //Encapsulate user data:
        UsernamePasswordToken token = new UsernamePasswordToken(username,password);

            try {
                subject.login(token);
                return "index";
            } catch (UnknownAccountException e) {
                model.addAttribute("msg","Incorrect user name");
                return "/user/login";
            }catch (IncorrectCredentialsException e){
                model.addAttribute("msg","Incorrect password");
                return "/user/login";
            }
    }

    @RequestMapping("/unauthorized")
    @ResponseBody
    public String unauthorized(){
        return "Insufficient permissions, unable to access!";
    }

    @RequestMapping("/logout")
    public String logout(){
        Subject subject = SecurityUtils.getSubject();
        subject.logout();
        return "user/login";
    }
}

It also involves the configuration of mybatis and the front-end page. These are self configured. It mainly explains the role and configuration of shiro.

Posted on Thu, 04 Nov 2021 16:46:51 -0400 by richclever