Spring Boot integrates Shiro

catalogue

1, Construction project

1. Create a SpringBoot project

2. Create configuration class

Custom UserRealm

ShiroConfig

3. index and login pages

4. controller layer programming

5. Implement authentication in UserRealm

Write resource access restrictions in ShiroConfig

  2, MD5, Salt registration

1. New register.html

2. New table t_user

3,application.yml

4. New entity class

5. New UserMapper

6. New service layer and SaltUtil

(1)UserService

(2)UserServiceImpl

(3)SaltUtil

(4)ShiroConstant

7. Write Controller

8. Write ShiroConfig

3, MD5, Salt certification

1. Write Service layer

2. Write UserRealm

3. Write ApplicationContextUtil

4. Write ShiroConfig

4, Shiro role based authorization

1. Create table

  2. Write entity classes for User and Role

3. Authoring Mapper layers

4. Write Service layer

5. Implement authorization in Realm

6. Write Index page

5, Shiro permission based authorization

1. New table new t_perm and t_role_permn table

  2. Write Role and Perms entity classes

3. Authoring Mapper layers

4. Write Service layer

5. Write userRealm

6. Write Index page

6, EhCache implementation cache

Shiro's introduction and basic use will not be introduced here

To get started, go to: Shiro quick start

1, Construction project

1. Create a SpringBoot project

  • When creating a new SpringBoot project, check web, thymeleaf and lombok

  Import dependent

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

2. Create configuration class

Custom UserRealm

public class UerRealm extends AuthorizingRealm {

    //to grant authorization
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        System.out.println("Authorization executed");
        
        return null;
    }

    //authentication
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        System.out.println("Certification performed");

        return null;

    }

}

ShiroConfig

This class is the core configuration class of Shiro, which inherits ShiroFilter, SecurityManager and the above customized Realm

@Configuration
public class ShiroConfig {

    //1. Create shiroFilter. / / it is responsible for intercepting all requests
    @Bean
    public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("getDefaultWebSecurityManager") DefaultWebSecurityManager defaultWebSecurityManager){
        ShiroFilterFactoryBean bean=new ShiroFilterFactoryBean();
        //Set up security manager
        bean.setSecurityManager(defaultWebSecurityManager);

        return bean;

    }

    //DefaultWebSecurityManager
    @Bean
    public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm") UserRealm uerRealm){
        DefaultWebSecurityManager securityManager=new DefaultWebSecurityManager();

        //Associate CustomerRealm
        securityManager.setRealm(uerRealm);

        return securityManager;
    }


    //Create a realm object
    @Bean
    public UserRealm getRealm(){
        return new UserRealm();
    }
}

Common filters in Shiro

Configuration abbreviationCorresponding filterfunction
anonAnonymousFilterSpecifies that the url can be accessed anonymously
authcFormAuthenticationFilterThe specified url requires form login. By default, the user name, password,rememberMe and other parameters will be obtained from the request and try to log in. If the login fails, it will jump to the path configured by loginUrl. We can also use this filter as the default login logic, but we usually write the login logic in the controller ourselves. If we write it ourselves, the error returned information can be customized.
authcBasicBasicHttpAuthenticationFilterThe specified url requires basic login
logoutLogoutFilterLog out of the filter and configure the specified url to realize the exit function, which is very convenient
noSessionCreationNoSessionCreationFilterDisable session creation
permsPermissionsAuthorizationFilterYou need to specify permissions to access
portPortFilterYou need to specify a port to access
restHttpMethodPermissionFilterConvert the http request method into the corresponding verb to construct a permission string. This doesn't make much sense. I'm interested in reading the comments of the source code
rolesRolesAuthorizationFilterYou need to specify a role to access
sslSslFilterAn https request is required to access
userUserFilterUsers who are logged in or remember me are required to access

3. index and login pages

<!DOCTYPE html>
<html lang="en"
      xmlns:th="https://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<h1>System home page</h1>

<ul>
    <li><a href="">user management </a></li>
    <li><a href="">Order management</a></li>
</ul>

</body>
</html>
<!DOCTYPE html>
<html lang="en"
      xmlns:th="https://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<h1>User login</h1>

<form th:action="${/login}" method="post">
        user name:<input type="text" name="username"> <br/>
        password: <input type="text" name="password"> <br>
        <input type="submit" value="Sign in">
</form>

</body>
</html>

4. controller layer programming

@Controller
public class MyController {
    
    @RequestMapping("/toLogin")
    public String toLogin(){
        return "login";
    }

    @RequestMapping("/toIndex")
    public String toLogin(){
        return "index";
    }


    @RequestMapping("/login")
    public String login(String username,String password){
        // Get current login user
        Subject subject = SecurityUtils.getSubject();

        try {
            // Perform login operation
            subject.login(new UsernamePasswordToken(username,password));
            // After passing the authentication, directly jump to index.html
            return "redirect:/toIndex";
        } catch (UnknownAccountException e) {
            e.printStackTrace();
            System.out.println("User name error~");
        } catch (IncorrectCredentialsException e) {
            e.printStackTrace();
            System.out.println("Password error~");
        } catch (Exception e) {
            e.printStackTrace();
        }
        // If the authentication fails, you still return to the login page
        return "redirect:/toLogin";
    }
}

5. Implement authentication in UserRealm

public class UserRealm extends AuthorizingRealm {
    // to grant authorization
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        return null;
    }

    // authentication
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        // Get the currently logged in topic
        String principal = (String) token.getPrincipal();
        // Simulate the data returned by the database
        if("admin".equals(principal)){
            return new SimpleAuthenticationInfo(principal,"123456",this.getName());
        }
        return null;
    }
}

In the above authentication, as long as the user name we enter is admin and the password is 123456, we can enter the home page through authentication

Write resource access restrictions in ShiroConfig

@Configuration
public class ShiroConfig {

    //1. Create shiroFilter. / / it is responsible for intercepting all requests
    @Bean
    public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("getDefaultWebSecurityManager") DefaultWebSecurityManager defaultWebSecurityManager){
        ShiroFilterFactoryBean bean=new ShiroFilterFactoryBean();
        //Set up security manager
        bean.setSecurityManager(defaultWebSecurityManager);

        //Configure system restricted resources
        //Configure system public resources
        Map<String,String> map = new HashMap<String,String>();
        map.put("/toIndex","anon");
        map.put("/toLogin","anon");  // When anon is set as a public resource, pay attention to the order of anon and authc
        map.put("/","authc");       //authc requires authentication and authorization to request this resource
        map.put("/index","authc");  //authc requires authentication and authorization to request this resource

        //Default authentication interface path
        shiroFilterFactoryBean.setLoginUrl("/toLogin");
        shiroFilterFactoryBean.setFilterChainDefinitionMap(map);


        return bean;

    }

    //DefaultWebSecurityManager
    @Bean
    public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm") UserRealm uerRealm){...}


    //Create a realm object
    @Bean
    public UserRealm userRealm(){...}
}

Test: it can be found that you cannot access / and / index directly without logging in, and you will jump to the login interface

  2, MD5, Salt registration

1. New register.html

<!DOCTYPE html>
<html lang="en"
      xmlns:th="https://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<h1>User registration</h1>

<form th:action="${/register}" method="post">
        user name:<input type="text" name="username"> <br/>
        password: <input type="text" name="password"> <br>
        <input type="submit" value="Register now">
</form>

</body>
</html>

2. New table t_user

DROP TABLE IF EXISTS `t_user`;
create table `t_user` (
	`id` int (11),
	`username` varchar (32),
	`password` varchar (32),
	`salt` varchar (32),
); 
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.12</version>
        </dependency>
    <!-- mybatis plus -->
        <dependency>
            <groupId>com.baomidou</groupId>
            <artifactId>mybatis-plus-boot-starter</artifactId>
            <version>3.4.1</version>
        </dependency>

3,application.yml

spring:
  datasource:
    type: com.alibaba.druid.pool.DruidDataSource
    druid:
      driver-class-name: com.mysql.jdbc.Driver
      url: jdbc:mysql://localhost:3306/shiro?useUnicode=true&characterEncoding=UTF-8&allowMultiQueries=true&serverTimezone=UTC
      username: root
      password: 123456
      # filters for monitoring statistical interception
      filters: stat,wall,log4j,config
      # Configure initialization size / min / Max
      initial-size: 5
      min-idle: 5
      max-active: 20
      # Get connection wait timeout
      max-wait: 60000
      # How often is the test performed to detect idle connections that need to be closed
      time-between-eviction-runs-millis: 60000
      # Minimum lifetime of a connection in the pool
      min-evictable-idle-time-millis: 300000
      validation-query: SELECT 'x'
      test-while-idle: true
      test-on-borrow: false
      test-on-return: false
      # Open PSCache and specify the size of PSCache on each connection. Set oracle to true and mysql to false. There are many sub databases and sub tables. It is recommended to set it to false
      pool-prepared-statements: false
      max-pool-prepared-statement-per-connection-size: 20
      
mybatis-plus:
  type-aliases-package: com.christy.shiro.entity
  configuration:
    map-underscore-to-camel-case: true

4. New entity class

@Data
@NoArgsConstructor
@AllArgsConstructor
public class User implements Serializable {
    /** The annotation cannot be less when the field self increment is set in the database**/
    @TableId(type = IdType.AUTO)
    private Integer id;

    private String username;

    private String password;

    private String salt;
}

5. New UserMapper

@Mapper
public interface UserMapper extends BaseMapper<User> {

}

6. New service layer and SaltUtil

(1)UserService

public interface UserService {

    void register(User user);
}

(2)UserServiceImpl

@Service
public class UserServiceImpl implements UserService {
    @Autowired
    private UserMapper userMapper;

    @Override
    public void register(User user) {
        // Generate random salt
        String salt = SaltUtil.getSalt(ShiroConstant.SALT_LENGTH);
        // Save random salt
        user.setSalt(salt);
        // Generate password
        Md5Hash password = new Md5Hash(user.getPassword(), salt, ShiroConstant.HASH_ITERATORS);
        // Save password
        user.setPassword(password.toHex());
        userMapper.insert(user);
    }
}

(3)SaltUtil

/**
 * User random salt generation tool class
 */
public class SaltUtil {

    public static String getSalt(int n){
        char[] chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz01234567890!@#$%^&*()".toCharArray();
        StringBuilder sb = new StringBuilder();
        for (int i = 0; i < n; i++) {
            char aChar = chars[new Random().nextInt(chars.length)];
            sb.append(aChar);
        }
        return sb.toString();
    }
}

(4)ShiroConstant

public class ShiroConstant {
    /** Number of random salt**/
    public static final int SALT_LENGTH = 8;
    /** hash Number of hashes**/
    public static final int HASH_ITERATORS = 1024;
    /** Encryption mode**/
    public interface HASH_ALGORITHM_NAME {
        String MD5 = "MD5";
    }

}

7. Write Controller

@Controller
public class MyController {

    @Autowired
    private UserService userService;
    
    @RequestMapping("/toLogin")
    public String toLogin(){...}

    @RequestMapping("/toRegister")
    public String toRegister(){...}

    @RequestMapping("/toIndex")
    public String toLogin(){...}

    @RequestMapping("/login")
    public String login(String username,String password){...}

    @RequestMapping("/register")
    public String register(User user){
        try {
            userService.register(user);
            return "redirect:/login.jsp";
        } catch (Exception e) {
            e.printStackTrace();
        }
        return "redirect:/register.jsp";
    }
}

8. Write ShiroConfig

@Configuration
public class ShiroConfig {

    //1. Create shiroFilter. / / it is responsible for intercepting all requests
    @Bean
    public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("getDefaultWebSecurityManager") DefaultWebSecurityManager defaultWebSecurityManager){
        ShiroFilterFactoryBean bean=new ShiroFilterFactoryBean();
        //Set up security manager
        bean.setSecurityManager(defaultWebSecurityManager);

        //Configure system restricted resources
        //Configure system public resources
        Map<String,String> map = new HashMap<String,String>();
        // When anon is set as a public resource, pay attention to the order of anon and authc
        map.put("/toIndex","anon");
        map.put("/toLogin","anon");
        map.put("/register","anon");
        map.put("/toRegister","anon");

        map.put("/","authc");
        map.put("/index","authc");  //authc requires authentication and authorization to request this resource

        //Default authentication interface path
        shiroFilterFactoryBean.setLoginUrl("/toLogin");
        shiroFilterFactoryBean.setFilterChainDefinitionMap(map);


        return bean;

    }

    //DefaultWebSecurityManager
    @Bean
    public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm") UserRealm uerRealm){...}


    //Create a realm object
    @Bean
    public UserRealm userRealm(){...}
}

Restart the project test: you can see that the password saved to the database by the registered department user is encrypted

3, MD5, Salt certification

1. Write Service layer

public interface UserService {
    ......Omit other methods

    User findUserByUserName(String userName);
}
@Service("userService")
public class UserServiceImpl implements UserService {
    ......Omit other methods

    @Override
    public User findUserByUserName(String userName) {
        return userMapper.findUserByUsername(userName);
    }
}

2. Write UserRealm

public class UserRealm extends AuthorizingRealm {
    // to grant authorization
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        return null;
    }

    // authentication
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        // Get the currently logged in user name
        String principal = (String) token.getPrincipal();
        // Since CustomerRealm is not managed by the factory, it cannot be managed by UserService
        UserService userService = (UserService) ApplicationContextUtil.getBean("userService");
        User user = userService.findUserByUserName(principal);
        if(!ObjectUtils.isEmpty(user)){
            return new SimpleAuthenticationInfo(user.getUsername(),user.getPassword(), new CustomerByteSource(user.getSalt()),this.getName());
        }
        return null;
    }
}

3. Write ApplicationContextUtil

@Component
public class ApplicationContextUtil implements ApplicationContextAware {
    public static ApplicationContext context;

    @Override
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.context = applicationContext;
    }

    /**
     * Get the class instance according to the class name in the factory
     */
    public static Object getBean(String beanName){
        return context.getBean(beanName);
    }
}

4. Write ShiroConfig

@Configuration
public class ShiroConfiguration {

    ......Omit other methods
    @Bean
    public UserRealm getRealm(){
        UserRealm userRealm = new UserRealm();
        // Set password matcher
        HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher();
        // Set encryption method
        credentialsMatcher.setHashAlgorithmName(ShiroConstant.HASH_ALGORITHM_NAME.MD5);
        // Sets the number of hashes
        credentialsMatcher.setHashIterations(ShiroConstant.HASH_ITERATORS);
        customerRealm.setCredentialsMatcher(credentialsMatcher);
        return uerRealm;
    }
}

Restart the project test: you can see that all accounts can log in

4, Shiro role based authorization

1. Create table

# The user table has been created before, so it will not be created here: t_user

DROP TABLE IF EXISTS `t_role`;
CREATE TABLE `t_role` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(64) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;


/*Table structure for table `t_user_role` */

DROP TABLE IF EXISTS `t_user_role`;
CREATE TABLE `t_user_role` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `user_id` int(8) DEFAULT NULL,
  `role_id` int(8) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=7 DEFAULT CHARSET=utf8;

t_user

 t_role

 t_user_role

  2. Write entity classes for User and Role

@Data
@NoArgsConstructor
@AllArgsConstructor
public class User{
    /** Other attributes are omitted**/
    private List<Role> roles = new ArrayList<>();
}
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Role{
    /** The annotation cannot be less when the field self increment is set in the database**/
    @TableId(type = IdType.AUTO)
    private Integer id;

    private String name;
}

3. Authoring Mapper layers

@Mapper
public interface UserMapper extends BaseMapper<User> {

    @Select("SELECT u.id,u.username,u.password,u.salt FROM t_user u WHERE u.username = #{username}")
    User findUserByUsername(String username);
}
@Mapper
public interface RoleMapper extends BaseMapper<Role> {
    @Select("select r.id,r.name from t_role r left join t_user_role ur on ur.role_id = r.id where ur.user_id = #{userId}")
    List<Role> getRolesByUserId(Integer userId);
}

4. Write Service layer

New RoleService and RoleServiceImpl

public interface RoleService {

    List<Role> getRolesByUserId(Integer userId);
}

@Service("roleService")
public class RoleServiceImpl implements RoleService {
    @Autowired
    private RoleMapper roleMapper;

    @Override
    public List<Role> getRolesByUserId(Integer userId) {
        return roleMapper.getRolesByUserId(userId);
    }
}

5. Implement authorization in Realm

public class UserRealm extends AuthorizingRealm {
    // to grant authorization
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        // Get primary identity information
        String principal = (String) principals.getPrimaryPrincipal();

        // According to user information
        UserService userService = (UserService) ApplicationContextUtil.getBean("userService");
        User user = userService.findUserByUserName(principal);

        //Obtain role information according to user id
        RoleService roleService = (RoleService) ApplicationContextUtil.getBean("roleService");
        List<Role> roles = roleService.getRolesByUserId(user.getId());

        //If the role information is not empty, add the role information
        if(!CollectionUtils.isEmpty(roles)){
            SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
            roles.forEach(role -> {
                simpleAuthorizationInfo.addRole(role.getName());
            });
            return simpleAuthorizationInfo;
        }
        return null;
    }

    /** Authentication code omitted**/
}

6. Write Index page

Please import the following dependencies before writing the page

        <!--thymeleaf Template-->
        <dependency>
            <groupId>com.github.theborakompanioni</groupId>
            <artifactId>thymeleaf-extras-shiro</artifactId>
            <version>2.0.0</version>
        </dependency>
<!DOCTYPE html>
<html lang="en"
      xmlns:th="https://www.thymeleaf.org"
      xmlns:shiro="https://www.thymeleaf.org/thymeleaf-extras-shiro">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<h1>System home page</h1>

<%--Need to import: xmlns:shiro="https://www.thymeleaf.org/thymeleaf-extras-shiro"--%>
 <%-- admin Users in the role can have the permissions of user management and order management at the same time, user Users in this role only have permission to manage orders --%>

<ul>
    <li shiro:hasAnyRole="admin,user"><a href="">Order management</a></li>
    <li shiro:hasRole="admin"><a href="">user management </a></li>
</ul>

</body>
</html>

Restart project test

5, Shiro permission based authorization

1. New table new t_perm and t_role_permn table

DROP TABLE IF EXISTS `t_perms`;
CREATE TABLE `t_perms` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `name` varchar(128) DEFAULT NULL,
  `url` varchar(255) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8;



DROP TABLE IF EXISTS `t_role_perms`;
CREATE TABLE `t_role_perms` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `role_id` int(11) DEFAULT NULL,
  `perms_id` int(11) DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=6 DEFAULT CHARSET=utf8;

t_perms

 t_role_perms

  2. Write Role and Perms entity classes

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Role {
    /** Other attribute fields are omitted**/

    private List<Permission> permissions = new ArrayList<>();
}
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Perms{
    /** The annotation cannot be less when the field self increment is set in the database**/
    @TableId(type = IdType.AUTO)
    private Integer id;
    private String name;
    private String url;
}

3. Authoring Mapper layers

@Mapper
public interface PermsMapper extends BaseMapper<Perms> {

    @Select("select p.id,p.name,p.url from t_perms p left join t_role_perms rp on rp.perms_id = p.id where rp.role_id = #{roleId}")
    List<Perms> getPermssByRoleId(Integer roleId);

}

4. Write Service layer

public interface PermsService {

    List<Perms> getPermsByRoleId(Integer roleId);

}
@Service("permissionService")
public class PermsServiceImpl implements PermsService {
    @Autowired
    private PermsMapper permsMapper;

    @Override
    public List<Perms> getPermssByRoleId(Integer roleId) {
        return permsMapper.getPermssByRoleId(roleId);
    }
}

5. Write userRealm

public class UserRealm extends AuthorizingRealm {
    // to grant authorization
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        // Get primary identity information
        String principal = (String) principals.getPrimaryPrincipal();
        // Obtain role information according to master identity information
        UserService userService = (UserService) ApplicationContextUtil.getBean("userService");
        User user = userService.findUserByUserName(principal);

        RoleService roleService = (RoleService) ApplicationContextUtil.getBean("roleService");
        List<Role> roles = roleService.getRolesByUserId(user.getId());
        if(!CollectionUtils.isEmpty(roles)){
            SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
            roles.forEach(role -> {
                simpleAuthorizationInfo.addRole(role.getName());
                PermissionService permissionService = (PermissionService) ApplicationContextUtil.getBean("permissionService");
                List<Permission> permissions = permissionService.getPermissionsByRoleId(role.getId());
                if(!CollectionUtils.isEmpty(permissions)){
                    permissions.forEach(permission -> {
                        simpleAuthorizationInfo.addStringPermission(permission.getName());
                    });
                }
            });
            return simpleAuthorizationInfo;
        }
        return null;
    }

    /** Authentication code omitted**/
}

6. Write Index page

<!DOCTYPE html>
<html lang="en"
      xmlns:th="https://www.thymeleaf.org"
      xmlns:shiro="https://www.thymeleaf.org/thymeleaf-extras-shiro">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

<h1>System home page</h1>

<%--Need to import: xmlns:shiro="https://www.thymeleaf.org/thymeleaf-extras-shiro"--%>
 <%-- admin Users in the role can have the permissions of user management and order management at the same time, user Users in this role only have permission to manage orders --%>

<ul>
    <li shiro:hasAnyRole="admin,user"><a href="">Order management</a></li>
    <li shiro:hasRole="admin"><a href="">user management </a></li>
</ul>

    <div shiro:hasPermission="user:add:*">
        <a th:href="@{/user/add}">increase</a>
    </div>

    <div shiro:hasPermission="admin:update:*">
        <a th:href="@{/user/update}">modify</a>
    </div>

    <div shiro:hasPermission="admin:delete:*">
        <a th:href="@{/user/update}">delete</a>
    </div>
    
    <div shiro:hasPermission="user:select:*">
        <a th:href="@{/user/update}">query</a>
    </div>

</body>
</html>

Restart project test

6, EhCache implementation cache

Still learning

If there is any mistake, I hope someone can point it out and spray it gently

Keywords: Java Shiro Spring Spring Boot

Added by ec on Thu, 11 Nov 2021 23:03:16 +0200