shiro introduction and use

Keywords: Programming Shiro Spring Session Ehcache

;

1, shiro internal structure

1. Components contained in shiro

shiro mainly includes Authenticator, authorizer, session manager, encryption, remember me and cache manager

2. Introduction to components of shiro

Subject: the subject, which can be understood as the user interacting with the application, contains all the information of the user, such as user information, user role, user authority, whether to log in, etc;
Security Manager: Security Manager shiro manages all modules of shiro through security manager.
Authenticator: authenticator, which is responsible for authenticating whether the user is a legal user. The specific authentication process of authenticator is to process whether the user is a legal user through realm;
Authorizer: authorizer, which is responsible for authorizing users. The specific authorization of authorizer is to obtain the permissions of users through realm;
Realm: you can have one or more realms, or you can customize the realm. In the shiro framework, the realm is very important to handle the user's authentication information and authorization information;
Session manager: responsible for session management;
SessionDAO: curd operation on session;
CacheManager: can cache user permission information to provide performance;
Cryptography: cryptographic module, which encrypts and saltes the password;

shiro manages the authenticator, authorizer, session manager, cache, sessionDao, realm through the securityManager authentication manager. The application side (app) interacts with the securityManager authentication manager through the subject. The authentication manager is responsible for proxy to the authenticator or authorizer. The authenticator authorizer finally obtains the user's authentication information or authorization information through the realm

2, pom files on which shiro depends

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

3, Using shiro as ini file

1. User authentication Demo

The content of shiro1.ini file is as follows

#Users impersonate real users
[users]
# Format user name = password
xiaoming=123
xiaohong=123456
    @Test
    public void testAuthenticate(){
        //1. Load ini file create IniSecurityManagerFactory from ini file
        IniSecurityManagerFactory managerFactory = new IniSecurityManagerFactory("classpath:shiro1.ini");
        //2. Get security manager
        SecurityManager instance = managerFactory.getInstance();
        //3. Bind the current SecurityManager to the current environment
        SecurityUtils.setSecurityManager(instance);
        //4. Get subject subject object
        Subject subject = SecurityUtils.getSubject();
        //5. Set user name and password
        UsernamePasswordToken token = new UsernamePasswordToken("xiaoming","123");
        //6. Log in
        subject.login(token);
        //7. Check whether the user logs in successfully true success false failure
        System.out.println(subject.isAuthenticated());
    }

2. User authorization Demo

The content of shiro2.ini file is as follows

#Users impersonate real users
[users]
# Format user name = password. For example, if the password of xiaoming is 123 and the role of admin corresponds to the role of user:save,user:delete,user:update,user:find
xiaoming=123,admin
xiaohong=123456,manager
#roles simulation role information
[roles]
#Format role name = the corresponding permissions of the role, such as admin role with user:save,user:delete,user:update,user:find permission manager role with user:find permission
admin=user:save,user:delete,user:update,user:find
manager=user:find
    @Test
    public void testAuthrizer(){
        //1. Load ini file create IniSecurityManagerFactory from ini file
        IniSecurityManagerFactory managerFactory = new IniSecurityManagerFactory("classpath:shiro2.ini");
        //2. Get security manager
        SecurityManager instance = managerFactory.getInstance();
        //3. Bind the current SecurityManager to the current environment
        SecurityUtils.setSecurityManager(instance);
        //4. Get subject subject object
        Subject subject = SecurityUtils.getSubject();
        //5. Set user name and password
        UsernamePasswordToken token = new UsernamePasswordToken("xiaohong","123456");
        //6. Log in
        subject.login(token);
        //7. View roles and permissions owned by users
        System.out.println(subject.hasRole("manager"));
        System.out.println(subject.isPermitted("user:update"));
    }

3. Custom realm Demo

The content of shiro3.ini file is as follows

[main]
#Declare custom realm name = custom realm class fully qualified name
customerRealm=com.xiao.shiro.CustomerRealm
#Register realm to Security Manager
securityManager.realms=$customerRealm

Custom realm

public class CustomerRealm extends AuthorizingRealm {
    //Customize the name of the realm because there may be more than one realm in the shiro framework. According to the name of the realm, decide which realm to use for processing
    @Override
    public void setName(String name) {
        super.setName("CustomerRealm");
    }
    //Authorization when the subject calls to get the user role, the method doGetAuthorizationInfo will be called
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        System.out.println("Authorization start");
        //User information can be obtained from principalCollection
        String primaryPrincipal = (String) principalCollection.getPrimaryPrincipal();
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        info.addRoles(Arrays.asList("manager","admin"));
        info.addStringPermission("user:update");
        return info;
    }
    //Authentication the method doGetAuthenticationInfo is called when the subject calls the user to log in
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        System.out.println("Start of certification");
        //When the user logs in, subject.login(token); the token type passed in is UsernamePasswordToken
        //So you can force the authenticationToken to UsernamePasswordToken
        UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
        String username = token.getUsername();
        String pwd = new String (token.getPassword());
        //The user name and password found from the database are xiaoming 123
        if ("xiaoming".equals(username) && "123".equals(pwd)) {
            //Authentication is achieved by storing the user information in the AuthenticationInfo object
            //The three parameters of SimpleAuthenticationInfo are as follows
            //1. Object principal user information can be any type of object
            //2. Object credentials password
            //3. String realmName the name of the current realm
            AuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(username,pwd,getName());
            return authenticationInfo;
        }
        //Exception thrown if authentication fails
        throw new RuntimeException("Login failed");
    }
}
    @Test
    public void testCustomerRealm(){
        //1. Load ini file create IniSecurityManagerFactory from ini file
        IniSecurityManagerFactory managerFactory = new IniSecurityManagerFactory("classpath:shiro3.ini");
        //2. Get security manager
        SecurityManager instance = managerFactory.getInstance();
        //3. Bind the current SecurityManager to the current environment
        SecurityUtils.setSecurityManager(instance);
        //4. Get subject subject object
        Subject subject = SecurityUtils.getSubject();
        //5. Set user name and password
        UsernamePasswordToken token = new UsernamePasswordToken("xiaoming","123");
        //6. When logging in the subject, the doGetAuthenticationInfo method in the realm will be called
        subject.login(token);
        //7. View the roles and permissions owned by the user. When the subject obtains the roles or permissions, it will call the doGetAuthorizationInfo method in the realm
        System.out.println(subject.hasRole("manager"));
        System.out.println(subject.isPermitted("user:find"));
    }

4. Use cache to save user role information and permission information Demo

Use ehcache as cache

shiro-ehcache.xml configuration information

<ehcache xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:noNamespaceSchemaLocation="../config/ehcache.xsd">
    <defaultCache
            maxElementsInMemory="1000"
            maxElementsOnDisk="10000000"
            eternal="false"
            overflowToDisk="false"
            diskPersistent="false"
            timeToIdleSeconds="120"
            timeToLiveSeconds="120"
            diskExpiryThreadIntervalSeconds="120"
            memoryStoreEvictionPolicy="LRU">
    </defaultCache>
</ehcache>
    @Test
    public void testCacheManager(){
        //1. Load ini file create IniSecurityManagerFactory from ini file
        IniSecurityManagerFactory managerFactory = new IniSecurityManagerFactory("classpath:shiro3.ini");
        //2. Get security manager if CacheManager is enabled, cachesecuritymanager object is required
        CachingSecurityManager instance = (CachingSecurityManager) managerFactory.getInstance();
        //3. Create cache management objects (ehcache is used for cache, so EhCacheManager is used) other cache objects can be used
        EhCacheManager ehCacheManager = new EhCacheManager();
        //4. Read ehcache configuration file
        ehCacheManager.setCacheManagerConfigFile("classpath:shiro-ehcache.xml");
        //5. Set the EhCacheManager object to the cacheingsecuritymanager Security Manager
        instance.setCacheManager(ehCacheManager);
        //6. Bind the current SecurityManager to the current environment
        SecurityUtils.setSecurityManager(instance);
        //7. Get subject subject object
        Subject subject = SecurityUtils.getSubject();
        //8. Set user name and password
        UsernamePasswordToken token = new UsernamePasswordToken("xiaoming","123");
        //9. Log in
        subject.login(token);
        //10. When viewing the roles and permissions owned by users, the first time they get permission information, they will call the doGetAuthorizationInfo method in the realm, and the second time they directly get from the cache, they will not walk away from the realm
        System.out.println(subject.hasRole("manager"));
        System.out.println(subject.isPermitted("user:find"));
    }

5. Clear cached user information

    @Test
    public void testCacheManager(){
        //1. Load ini file create IniSecurityManagerFactory from ini file
        IniSecurityManagerFactory managerFactory = new IniSecurityManagerFactory("classpath:shiro3.ini");
        //2. Get security manager if CacheManager is enabled, cachesecuritymanager object is required
        CachingSecurityManager instance = (CachingSecurityManager) managerFactory.getInstance();
        //3. Create cache management objects (ehcache is used for cache, so EhCacheManager is used) other cache objects can be used
        EhCacheManager ehCacheManager = new EhCacheManager();
        //4. Read ehcache configuration file
        ehCacheManager.setCacheManagerConfigFile("classpath:shiro-ehcache.xml");
        //5. Set the EhCacheManager object to the cacheingsecuritymanager Security Manager
        instance.setCacheManager(ehCacheManager);
        //6. Bind the current SecurityManager to the current environment
        SecurityUtils.setSecurityManager(instance);
        //7. Get subject subject object
        Subject subject = SecurityUtils.getSubject();
        //8. Set user name and password
        UsernamePasswordToken token = new UsernamePasswordToken("xiaoming","123");
        //9. Log in
        subject.login(token);
        //10. When viewing the roles and permissions owned by users, the first time they get permission information, they will call the doGetAuthorizationInfo method in the realm, and the second time they directly get from the cache, they will not walk away from the realm
        System.out.println(subject.hasRole("manager"));
        System.out.println(subject.isPermitted("user:find"));
        //Get ehcache user cache information
        Cache<Object, Object> cache = ehCacheManager.getCache("CustomerRealm.authorizationCache");
        //Clear the corresponding cache information of xiaoming user
        cache.remove(new SimplePrincipalCollection("xiaoming", "CustomerRealm"));
        //Get user role and permission information from the realm after clearing the cache
        System.out.println(subject.hasRole("manager"));
        System.out.println(subject.isPermitted("user:find"));
    }

3, Integrating shiro with springboot

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.xiao.shiro</groupId>
    <artifactId>shirodemo</artifactId>
    <version>1.0-SNAPSHOT</version>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.2.1.RELEASE</version>
    </parent>
    <dependencies>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>1.3.1</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.13</version>
        </dependency>
        <dependency>
            <groupId>tk.mybatis</groupId>
            <artifactId>mapper-spring-boot-starter</artifactId>
            <version>2.0.2</version>
        </dependency>
        <!--shiro core-->
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-core</artifactId>
            <version>1.3.2</version>
        </dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>commons-logging</groupId>
            <artifactId>commons-logging</artifactId>
            <version>1.1.3</version>
        </dependency>
        <!-- ehcache -->
        <dependency>
            <groupId>net.sf.ehcache</groupId>
            <artifactId>ehcache-core</artifactId>
            <version>2.6.11</version>
        </dependency>
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-all</artifactId>
            <version>1.3.2</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.44</version>
        </dependency>
        <!--spring and shiro integration -->
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-spring</artifactId>
            <version>1.3.2</version>
        </dependency>
        <!--shiro And redis integration-->
        <dependency>
            <groupId>org.crazycake</groupId>
            <artifactId>shiro-redis</artifactId>
            <version>3.0.0</version>
        </dependency>
        <!--thymeleaf -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
    </dependencies>

</project>

2. Custom realm

public class CustomerRealm extends AuthorizingRealm {
    @Autowired
    private UserInfoService userInfoService;
    //Customize the name of the realm because there may be more than one realm in the shiro framework. According to the name of the realm, decide which realm to use for processing
    @Override
    public void setName(String name) {
        super.setName("CustomerRealm");
    }
    //Authorization when the subject calls to get the user role, the method doGetAuthorizationInfo will be called
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        System.out.println("Authorization start");
        //User information can be obtained from principalCollection
        UserInfo userInfo = (UserInfo) principalCollection.getPrimaryPrincipal();
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        UserDto userExtInfo = userInfoService.findUserExtInfo(userInfo.getId());
        info.addRoles(userExtInfo.getRoles());
        info.addStringPermissions(userExtInfo.getPermissions());
        return info;
    }
    //Authentication the method doGetAuthenticationInfo is called when the subject calls the user to log in
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        System.out.println("Start of certification");
        //When the user logs in, subject.login(token); the token type passed in is UsernamePasswordToken
        //So you can force the authenticationToken to UsernamePasswordToken
        UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
        String username = token.getUsername();
        String pwd = new String (token.getPassword());
        UserInfo user = userInfoService.findUserByUserNameAndPwd(username, pwd);
        //The user name and password found from the database are xiaoming 123
        if (user != null) {
            //Authentication is achieved by storing the user information in the AuthenticationInfo object
            //The three parameters of SimpleAuthenticationInfo are as follows
            //1. Object principal user information can be any type of object
            //2. Object credentials password
            //3. String realmName the name of the current realm
            AuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(user, pwd, getName());
            return authenticationInfo;
        }
        //Exception thrown if authentication fails
        throw new RuntimeException("Login failed");
    }
}

3. shiro configuration class

@Configuration
public class ShiroConfig {
    //Give the custom realm to the spring container for management
    @Bean
    public CustomerRealm getCustomerRealm(){
        return new CustomerRealm();
    }

    @Bean
    public SecurityManager getSecurityManager(CustomerRealm realm){
        //Create a security manager and give the realm to the manager for management
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(realm);
        return securityManager;
    }

  
    //Configure shiro filter conditions and jump page
    @Bean
    public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager){
        ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
        //Set up security manager
        bean.setSecurityManager(securityManager);
        //Login page
        bean.setLoginUrl("/tologin");
        //Authorization failure jump page
        bean.setUnauthorizedUrl("/toUnauthorized");
        //LinkedHashMap must be used to ensure the order of filtering
        Map<String, String> map = new LinkedHashMap<>();
        //anon anonymous access means access without login and authorization
        //authc requires authentication login to access
        //Logout logout logout logout to jump to the page set by bean.setLoginUrl() method
        //perms[xx] has xx permission to access
        //roles[xx] can only be accessed by roles of xx
        map.put("/user/index", "anon");
        //Indicates that you have select user permission to access
        map.put("/user/select", "perms[select-user]");
        //Represents the role of system administrator to access
        map.put("/user/delete", "roles[system administrator]");
        //Only authentication login can access
        map.put("/user/**", "authc");
        //Set the filter chain of the request. The filter chain needs to be authenticated in order. It is usually placed after anonymous access
        bean.setFilterChainDefinitionMap(map);
        return bean;
    }
}

4. Test controller

@Controller
public class TestController {
    @RequestMapping("/login")
    public String login(UserInfo userInfo) {
        try {
            UsernamePasswordToken upt = new UsernamePasswordToken(userInfo.getUsername(), userInfo.getPassword());
            SecurityUtils.getSubject().login(upt);
            return "Login successful";
        } catch (Exception e) {
            e.printStackTrace();
            return "Login failed";
        }
    }

    @RequestMapping("/user/index")
    @ResponseBody
    public String index(){
        return "visit index success";
    }

    @RequestMapping("/user/select")
    @ResponseBody
    public String select(){
        return "visit select success";
    }

    @RequestMapping("/user/delete")
    @ResponseBody
    public String delete(){
        return "visit delete success";
    }

    @RequestMapping("/user/login")
    @ResponseBody
    public String login(){
        return "visit login success";
    }
    //Skip landing page
    @RequestMapping("/tologin")
    public String tologin(){
        return "login";
    }
    //Skip unauthorized page
    @RequestMapping("/toUnauthorized")
    public String toUnauthorized(){
        return "unauthorized";
    }
}

5. Permission control by shiro annotation

(1) . add a dependency to the pom file by referring to the above dependency

(2) The shiro configuration class adds the configuration of the two objects DefaultAdvisorAutoProxyCreator and AuthorizationAttributeSourceAdvisor

@Configuration
public class ShiroConfig {
    //To enable shiro annotation, you need to configure two objects: DefaultAdvisorAutoProxyCreator and AuthorizationAttributeSourceAdvisor
    @Bean
    public DefaultAdvisorAutoProxyCreator getDefaultAdvisorAutoProxyCreator() {
        DefaultAdvisorAutoProxyCreator autoProxyCreator = new DefaultAdvisorAutoProxyCreator();
        //Turn on proxy for spring AOP
        autoProxyCreator.setProxyTargetClass(true);
        return autoProxyCreator;
    }

    @Bean
    public CustomerRealm getCustomerRealm(){
        return new CustomerRealm();
    }

    @Bean
    public SecurityManager getSecurityManager(CustomerRealm realm){
        //Create a security manager and give the realm to the manager for management
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(realm);
        return securityManager;
    }

    //Configure launch shiro annotation
    @Bean
    public AuthorizationAttributeSourceAdvisor  getAuthorizationAttributeSourceAdvisor(SecurityManager securityManager) {
        AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();
        advisor.setSecurityManager(securityManager);
        return advisor;
    }
    //Configure shiro filter conditions and jump page
    @Bean
    public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager){
        ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
        //Set up security manager
        bean.setSecurityManager(securityManager);
        //Login page
        bean.setLoginUrl("/tologin");
        //Authorization failure jump page
        bean.setUnauthorizedUrl("/toUnauthorized");
        //LinkedHashMap must be used to ensure the order of filtering
        Map<String, String> map = new LinkedHashMap<>();
        //anon anonymous access means access without login and authorization
        //authc requires authentication login to access
        //Logout logout logout logout to jump to the page set by bean.setLoginUrl() method
        //perms[xx] has xx permission to access
        //roles[xx] can only be accessed by roles of xx
        map.put("/user/index", "anon");
        map.put("/login", "anon");
        //Indicates that you have select user permission to access
        map.put("/user/select", "perms[select-user]");
        //Represents the role of system administrator to access
        map.put("/user/delete", "roles[system administrator]");
        //Only authentication login can access
        map.put("/**", "authc");
        //Set the filter chain of the request. The filter chain needs to be authenticated in order. It is usually placed after anonymous access
        bean.setFilterChainDefinitionMap(map);
        return bean;
    }

(3) , test controller

@Controller
public class TestController {
   
    //Skip landing page
    @RequestMapping("/tologin")
    public String tologin(){
        return "login";
    }
    //Skip unauthorized page
    @RequestMapping("/toUnauthorized")
    public String toUnauthorized(){
        return "unauthorized";
    }

    //User add and user delete permission are available to access
    @RequiresPermissions(value = {"user-add","user-delete"})
    @RequestMapping("/testPermission")
    @ResponseBody
    public String testPermission(){
        return "test  Permission success";
    }

    //Only administrator role can access
    @RequiresRoles(value = "administrators")
    @RequestMapping("/testRoles")
    @ResponseBody
    public String tesRoles(){
        return "test  role success";
    }
}

shiro's method based on filter chain (such as map.put("/**", "authc")) is different from that based on annotation (such as @ RequiresRoles) when they no longer have access

If you do not have permission, you will jump to the address set by setunauthorized URL ("/ tounauthorized")

If you do not have permission to annotate, you will throw an AuthorizationException exception. You can customize a global exception to handle annotation. The code is as follows

@ControllerAdvice
public class CustomerExceptionHandler {
    //Catch an exception of type AuthorizationException
    @ExceptionHandler(value = AuthorizationException.class)
    @ResponseBody
    public String error(HttpServletRequest request, HttpServletResponse response,AuthorizationException e) {
		return "Unauthorized";
    }
}

4, shiro password encryption

 public static void main(String[] args) {
        //The three parameters are as follows
        //1. Object source original password
        //2. Object salt value
        //3. int hashIterations salt several times
        Md5Hash pwd = new Md5Hash("12345", "salt", 2);
        System.out.println(pwd.toString());
    }

5, Spring boot integrates session management of shiro to store sessions in redis

shiro provides three default implementations of session manager by default

(1) . DefaultSessionManager: for Java se environment
(2) . ServletContainerSessionManager: used in the web environment. By default, the web environment uses this implementation class session information in the httpSession
(3) . DefaultWebSessionManager: used in the web environment. The session information can be stored in the specified place, such as mysql and redis

1. Introducing Shiro redis dependency

<dependency>
   <groupId>org.crazycake</groupId>
   <artifactId>shiro-redis</artifactId>
   <version>3.0.0</version>
</dependency>

2. Introduce redis configuration into application.yml

 spring: 
	redis:
		host: 127.0.0.1
		port: 6379

3. Customize shiro session manager

public class CustomerSessionManager extends DefaultWebSessionManager {
    /**
     * sessionid in header information
     *      Request header: Authorization: sessionid
     *
     * Specify how to get sessionId
     */
    @Override
    protected Serializable getSessionId(ServletRequest request, ServletResponse response) {
        //Get data in request header Authorization
        String id = WebUtils.toHttp(request).getHeader("Authorization");
        if(StringUtils.isEmpty(id)) {
            //If it is not carried, a new sessionId will be generated
            return super.getSessionId(request,response);
        }else{
            //Specify the source of sessionId specify to get sessionId from the request header do not specify to get sessionId from the cookie by default
            request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_SOURCE, "header");
            //sessionId
            request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID, id);
            request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_IS_VALID, Boolean.TRUE);
            return id;
        }
    }
}

4. Configure shiro session management to store in redis

package com.xiao.shiro.config;

import com.xiao.shiro.realm.CustomerRealm;
import com.xiao.shiro.session.CustomerSessionManager;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.spring.LifecycleBeanPostProcessor;
import org.apache.shiro.spring.security.interceptor.AuthorizationAttributeSourceAdvisor;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.crazycake.shiro.RedisCacheManager;
import org.crazycake.shiro.RedisManager;
import org.crazycake.shiro.RedisSessionDAO;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.Map;

@Configuration
public class ShiroConfig {


    @Bean
    public CustomerRealm getCustomerRealm(){
        return new CustomerRealm();
    }

    @Bean
    public SecurityManager getSecurityManager(CustomerRealm realm){
         //Create a security manager and give the realm to the manager for management
         DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(realm);
        //Register a custom session manager with the Security Manager
        securityManager.setSessionManager(sessionManager());
        //Register the customized redis cache manager to the Security Manager
        securityManager.setCacheManager(cacheManager());
        return securityManager;
    }

    //Configure launch shiro annotation
    @Bean
    public AuthorizationAttributeSourceAdvisor  getAuthorizationAttributeSourceAdvisor(SecurityManager securityManager) {
        AuthorizationAttributeSourceAdvisor advisor = new AuthorizationAttributeSourceAdvisor();
        advisor.setSecurityManager(securityManager);
        return advisor;
    }
    //Configure shiro filter conditions and jump page
    @Bean
    public ShiroFilterFactoryBean shiroFilterFactoryBean(SecurityManager securityManager){
        ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
        //Set up security manager
        bean.setSecurityManager(securityManager);
        //Login page
        bean.setLoginUrl("/tologin");
        //Authorization failure jump page
        bean.setUnauthorizedUrl("/toUnauthorized");
        //LinkedHashMap must be used to ensure the order of filtering
        Map<String, String> map = new LinkedHashMap<>();
        //anon anonymous access means access without login and authorization
        //authc requires authentication login to access
        //Logout logout logout logout to jump to the page set by bean.setLoginUrl() method
        //perms[xx] has xx permission to access
        //roles[xx] can only be accessed by roles of xx
        map.put("/user/index", "anon");
        map.put("/login", "anon");
        //Indicates that you have select user permission to access
        map.put("/user/select", "perms[select-user]");
        //Represents the role of system administrator to access
        map.put("/user/delete", "roles[system administrator]");
        //Only authentication login can access
        map.put("/**", "authc");
        //Set the filter chain of the request. The filter chain needs to be authenticated in order. It is usually placed after anonymous access
        bean.setFilterChainDefinitionMap(map);
        return bean;
    }

    //To enable shiro annotation, you need to configure two objects: DefaultAdvisorAutoProxyCreator and AuthorizationAttributeSourceAdvisor
    @Bean
    public DefaultAdvisorAutoProxyCreator getDefaultAdvisorAutoProxyCreator() {
        DefaultAdvisorAutoProxyCreator autoProxyCreator = new DefaultAdvisorAutoProxyCreator();
        //Turn on proxy for spring AOP
        autoProxyCreator.setProxyTargetClass(true);
        return autoProxyCreator;
    }


    @Value("${spring.redis.host}")
    private String host;
    @Value("${spring.redis.port}")
    private int port;

    /**
     * 1.redis Operating redis
     */
    public RedisManager redisManager() {
        RedisManager redisManager = new RedisManager();
        redisManager.setHost(host);
        redisManager.setPort(port);
        return redisManager;
    }

    /**
     * 2.sessionDao
     */
    public RedisSessionDAO redisSessionDAO() {
        RedisSessionDAO sessionDAO = new RedisSessionDAO();
        sessionDAO.setRedisManager(redisManager());
        return sessionDAO;
    }

    /**
     * 3.Session manager
     */
    public DefaultWebSessionManager sessionManager() {
        CustomerSessionManager sessionManager = new CustomerSessionManager();
        sessionManager.setSessionDAO(redisSessionDAO());
        return sessionManager;
    }

    /**
     * 4.Cache manager
     */
    public RedisCacheManager cacheManager() {
        RedisCacheManager redisCacheManager = new RedisCacheManager();
        redisCacheManager.setRedisManager(redisManager());
        return redisCacheManager;
    }
}

5,AuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(user, pwd, getName());

The user object here implements two interfaces: serializable and authcacheprincipal

public class UserInfo implements Serializable,AuthCachePrincipal {
    private Long id;
    private String username;
    private String password;

    public Long getId() {
        return id;
    }

    public void setId(Long id) {
        this.id = id;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }
    //Just write getAuthCacheKey method
    @Override
    public String getAuthCacheKey() {
        return null;
    }

Posted by MrSheen on Fri, 15 May 2020 01:50:42 -0700