Spring boot integrates Shiro -- authentication and authorization

Shiro

1, introduction

  • Apache Shiro is a Java Security (permission) framework.
  • Shiro can easily develop good enough applications, which can be used not only in Java se environment, but also in Java EE environment.
  • Shiro can complete authentication, authorization, encryption, session management, Web integration, caching, etc.
  • Download address: https://shiro.apache.org/

2. Operation principle

Subject: the subject actually represents the User who is currently executing the operation, just because "User" generally refers to a person, but a "subject" can be a person, any third-party system, service account and any other third-party software system that is interacting with the current system.

SecurityManager: Security Manager. That is, all security related operations will interact with SecurityManager, and it manages all subject s.

Realm: there can be one or more realms, which can be considered as a secure entity data source, that is, used to obtain secure entities.

3. Shiro filter

Shiro has built-in filter, which can implement the permission related interceptor.

Common filters Explain
anon Access without authentication (login)
authc Must be authenticated to access
user If you use the function of rememberMe, you can access it directly
perms Have access to a resource
roles Have a role to access

4. Spring boot integrates Shiro

4.1. Add dependency

 <!-- mybatis -->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.1.2</version>
        </dependency>

        <!-- druid-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid-spring-boot-starter</artifactId>
            <version>1.1.21</version>
        </dependency>


        <!-- mysql-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
        </dependency>

        <!--jdbc -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-jdbc</artifactId>
        </dependency>

        <!-- spring-boot-starter-web -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>

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

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>

4.2 Shiro configuration class

@Configuration
public class ShiroConfig {
    /**
     * Create ShiroFilterFactoryBean
     */
    @Bean
    public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager") DefaultWebSecurityManager securityManager){
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        //Set up security manager
        shiroFilterFactoryBean.setSecurityManager(securityManager);
        //Add shiro built in filter
        /**
         * Shiro The built-in filter can realize the authority related amount interceptor
         *      Common filters:
         *      anon:Access without authentication (login)
         *      authc:Must be authenticated to access
         *      user:If you use the function of rememberMe, you can access it directly
         *      perms:The resource must have resource permission to access
         *      role:The resource must have role permission to access
         */
        Map<String,String> filterMap = new LinkedHashMap<>();
        //Authentication interception
        filterMap.put("/add","authc");
        filterMap.put("/update","authc");
        //Authorized interception
        filterMap.put("/add","perms[user:add]");
        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterMap);

        //Modify the page of the blocked request jump
        shiroFilterFactoryBean.setLoginUrl("/toLogin");
        //Set unauthorized pages
        shiroFilterFactoryBean.setUnauthorizedUrl("/nuAuth");
        return shiroFilterFactoryBean;
    }

    /**
     * Create defaultwebseriarymanager
     */
    @Bean(name = "securityManager")
    public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm){
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        //Correlation realm
        securityManager.setRealm(userRealm);
        return securityManager;
    }

    /**
     * Create Rrealm
     */
    @Bean(name = "userRealm")
    public UserRealm getRealm(){
        return new UserRealm();
    }
}

4.3. Custom Realm

(1) AuthenticatingRealm: shiro's domain for authentication, which implements the authentication logic when users log in with the dogetauthenticationinfo method; (2) Authorizing realm: shiro is used in the field of authorization. It implements the dogetauthorizationinfo method to realize the authorization logic of users. Authorizing realm inherits authenticating realm, so it is mainly used in actual use; (3) AuthenticatingRealm and AuthorizingRealm are the two classes that provide some thread's realm interfaces in shiro (4) In the integration project with spring, shiro's SecurityManager will automatically call these two methods to realize authentication and authorization. The authentication and authorization information can be saved in the cache in combination with shiro's CacheManager.

public class UserRealm extends AuthorizingRealm {

    @Autowired
    private UserService userService;

    /**
     * Execute authorization logic
     * @param principalCollection
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        //Empower resources
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        //Add the authorization string of the resource, which should be the same as the authorization intercepting string
        info.addStringPermission("user:add");
        return info;
    }

    /**
     * Execute authentication logic
     * @param authenticationToken
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        //Write shiro judgment logic to judge user name and password
        UsernamePasswordToken token = (UsernamePasswordToken)authenticationToken;
        User user = userService.findByName(token.getUsername());
        //Judge user name
        if(user == null){
            //The user name does not exist, and shiro will throw unknown accountexception for us
            return null;
        }

        //To determine the password, shiro will help us determine whether the password is the same as the password in the database
        return new SimpleAuthenticationInfo("",user.getPassword(),"");
    }
}

4.4 login controller

/**
     * Logon logic
     * @param username
     * @param password
     * @return
     */
    @RequestMapping("/login")
    public String login(@RequestParam("username") String username,
                        @RequestParam("password") String password,
                        Model model){
        /**
         * Using shiro to write authentication operations
         */
        //Get subject
        Subject subject = SecurityUtils.getSubject();
        //Encapsulate user data
        UsernamePasswordToken token = new UsernamePasswordToken(username, password);
        //Execute login method
        try {
            subject.login(token);
            //If there is no exception, login succeeded
            return "/test";
        }catch (UnknownAccountException e){
            //If there is an exception, the login fails. If an unknown accountexception occurs, the user name does not exist
            model.addAttribute("msg","user name does not exist");
            return "/toLogin";
        }catch (IncorrectCredentialsException e){
            //If IncorrectCredentialsException occurs, the password is wrong
            model.addAttribute("msg","Password error");
            return "/toLogin";
        }

    }

Keywords: Programming Shiro Spring Java Apache

Added by BKPARTIES on Sun, 22 Mar 2020 13:59:52 +0200