Spring Boot learning notes - Spring Boot integration Shiro

Spring Boot learning

Official website: https://spring.io/projects/spring-boot#overview

file: https://docs.spring.io/spring-boot/docs/2.2.6.RELEASE/reference/html/

Reference video: [crazy God says Java] the latest tutorial of SpringBoot, IDEA version, is easy to understand_ Beep beep beep_ bilibili

Project complete reference code: lexiaoyuan/SpringBootStudy: My Spring Boot study notes (github.com),Springboot study: my Spring Boot study notes (gitee.com)

meet Spring Boot learning notes - Spring Boot integration Shiro (I)

[supplement] install Easy Code plug-in

Introduction: https://gitee.com/makejava/EasyCode

  • In the plug-in market in settings, search Easy Code, click Install, and restart IDEA after installation. (I have installed it here)

Integrate MyBatis

  • First, open mysql to ensure that idea can be connected.

  • In POM Import some dependencies into XML

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-thymeleaf</artifactId>
    </dependency>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-web</artifactId>
    </dependency>
    <dependency>
        <groupId>org.apache.shiro</groupId>
        <artifactId>shiro-spring</artifactId>
        <version>1.5.2</version>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-jdbc</artifactId>
    </dependency>
    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <scope>runtime</scope>
    </dependency>
    <dependency>
        <groupId>org.mybatis.spring.boot</groupId>
        <artifactId>mybatis-spring-boot-starter</artifactId>
        <version>2.1.2</version>
    </dependency>
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>druid</artifactId>
        <version>1.1.22</version>
    </dependency>
    <dependency>
        <groupId>log4j</groupId>
        <artifactId>log4j</artifactId>
        <version>1.2.17</version>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
        <exclusions>
            <exclusion>
                <groupId>org.junit.vintage</groupId>
                <artifactId>junit-vintage-engine</artifactId>
            </exclusion>
        </exclusions>
    </dependency>
</dependencies>
  • Use the Easy Code plug-in to generate code. Just follow the following figure


  • Directory after code generation, where userserviceimpl The Java directory has been adjusted

  • Configure the data source and MyBatis, and create a new application in the resources directory YML file
# Configure data sources
spring:
  datasource:
    url: jdbc:mysql://localhost:3306/mybatis?useUnicode=true&characterEncoding=utf-8&serverTimezone=UTC
    username: root
    password: 123456
    driver-class-name: com.mysql.cj.jdbc.Driver
    type: com.alibaba.druid.pool.DruidDataSource  # Custom data source

    #Spring Boot does not inject these attribute values by default and needs to bind itself
    #druid data source proprietary configuration
    initialSize: 5
    minIdle: 5
    maxActive: 20
    maxWait: 60000
    timeBetweenEvictionRunsMillis: 60000
    minEvictableIdleTimeMillis: 300000
    validationQuery: SELECT 1 FROM DUAL
    testWhileIdle: true
    testOnBorrow: false
    testOnReturn: false
    poolPreparedStatements: true

    #Configure filters for monitoring statistics interception, stat: monitoring statistics, log4j: logging, wall: defending sql injection
    filters: stat,wall,log4j
    maxPoolPreparedStatementPerConnectionSize: 20
    useGlobalDataSourceStat: true
    connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=500

# MyBatis configuration
mybatis:
  type-aliases-package: com.springboot.entity
  mapper-locations: classpath:mapper/*.xml
  • In user Add a toString method in Java
/**
 * (User)Entity class
 */
public class User{

    private Integer id;
    
    private String name;
    
    private String pwd;


    public Integer getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getPwd() {
        return pwd;
    }

    public void setPwd(String pwd) {
        this.pwd = pwd;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", pwd='" + pwd + '\'' +
                '}';
    }
}
  • In userdao Add some code to Java
/**
 * (User)Table database access layer
 */
@Repository
@Mapper
public interface UserDao {

    /**
     * Query a single piece of data by ID
     *
     * @param id Primary key
     * @return Instance object
     */
    User queryById(Integer id);

    User queryByName(String name);

    /**
     * Query specified row data
     *
     * @param offset Query start position
     * @param limit Number of queries
     * @return Object list
     */
    List<User> queryAllByLimit(@Param("offset") int offset, @Param("limit") int limit);


    /**
     * Query by entity as filter criteria
     *
     * @param user Instance object
     * @return Object list
     */
    List<User> queryAll(User user);

    /**
     * New data
     *
     * @param user Instance object
     * @return Number of affected rows
     */
    int insert(User user);

    /**
     * Modify data
     *
     * @param user Instance object
     * @return Number of affected rows
     */
    int update(User user);

    /**
     * Delete data through primary key
     *
     * @param id Primary key
     * @return Number of affected rows
     */
    int deleteById(Integer id);

}
  • In userservice A queryByName method is also added to Java
/**
 * (User)Table service interface
 */
public interface UserService {

    /**
     * Query a single piece of data by ID
     *
     * @param id Primary key
     * @return Instance object
     */
    User queryById(Integer id);

    User queryByName(String name);

    /**
     * Query multiple data
     *
     * @param offset Query start position
     * @param limit Number of queries
     * @return Object list
     */
    List<User> queryAllByLimit(int offset, int limit);

    /**
     * New data
     *
     * @param user Instance object
     * @return Instance object
     */
    User insert(User user);

    /**
     * Modify data
     *
     * @param user Instance object
     * @return Instance object
     */
    User update(User user);

    /**
     * Delete data through primary key
     *
     * @param id Primary key
     * @return Is it successful
     */
    boolean deleteById(Integer id);

}
  • In userserviceimpl A queryByName method is also added to Java
/**
 * (User)Table service implementation class
 */
@Service("userService")
public class UserServiceImpl implements UserService {
    @Resource
    private UserDao userDao;

    /**
     * Query a single piece of data by ID
     *
     * @param id Primary key
     * @return Instance object
     */
    @Override
    public User queryById(Integer id) {
        return this.userDao.queryById(id);
    }

    @Override
    public User queryByName(String name) {
        return this.userDao.queryByName(name);
    }

    /**
     * Query multiple data
     *
     * @param offset Query start position
     * @param limit Number of queries
     * @return Object list
     */
    @Override
    public List<User> queryAllByLimit(int offset, int limit) {
        return this.userDao.queryAllByLimit(offset, limit);
    }

    /**
     * New data
     *
     * @param user Instance object
     * @return Instance object
     */
    @Override
    public User insert(User user) {
        this.userDao.insert(user);
        return user;
    }

    /**
     * Modify data
     *
     * @param user Instance object
     * @return Instance object
     */
    @Override
    public User update(User user) {
        this.userDao.update(user);
        return this.queryById(user.getId());
    }

    /**
     * Delete data through primary key
     *
     * @param id Primary key
     * @return Is it successful
     */
    @Override
    public boolean deleteById(Integer id) {
        return this.userDao.deleteById(id) > 0;
    }
}
  • In userdao An SQL statement of queryByName is also added to XML
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.springboot.dao.UserDao">

    <resultMap type="com.springboot.entity.User" id="UserMap">
        <result property="id" column="id" jdbcType="INTEGER"/>
        <result property="name" column="name" jdbcType="VARCHAR"/>
        <result property="pwd" column="pwd" jdbcType="VARCHAR"/>
    </resultMap>

    <!--Query single-->
    <select id="queryById" resultMap="UserMap">
        select
          id, name, pwd
        from mybatis.user
        where id = #{id}
    </select>

    <select id="queryByName" parameterType="String" resultType="user">
        select
          id, name, pwd
        from mybatis.user
        where name = #{name}
    </select>

    <!--Query specified row data-->
    <select id="queryAllByLimit" resultMap="UserMap">
        select
          id, name, pwd
        from mybatis.user
        limit #{offset}, #{limit}
    </select>

    <!--Query by entity as filter criteria-->
    <select id="queryAll" resultMap="UserMap">
        select
          id, name, pwd
        from mybatis.user
        <where>
            <if test="id != null">
                and id = #{id}
            </if>
            <if test="name != null and name != ''">
                and name = #{name}
            </if>
            <if test="pwd != null and pwd != ''">
                and pwd = #{pwd}
            </if>
        </where>
    </select>

    <!--Add all columns-->
    <insert id="insert" keyProperty="id" useGeneratedKeys="true">
        insert into mybatis.user(name, pwd)
        values (#{name}, #{pwd})
    </insert>

    <!--Modify data through primary key-->
    <update id="update">
        update mybatis.user
        <set>
            <if test="name != null and name != ''">
                name = #{name},
            </if>
            <if test="pwd != null and pwd != ''">
                pwd = #{pwd},
            </if>
        </set>
        where id = #{id}
    </update>

    <!--Delete by primary key-->
    <delete id="deleteById">
        delete from mybatis.user where id = #{id}
    </delete>

</mapper>
  • First, test it in the test class
@SpringBootTest
class Springboot08ShiroApplicationTests {

    @Autowired
    private UserServiceImpl userService;

    @Test
    void contextLoads() {
        System.out.println(userService.queryById(1).toString());
    }

}
  • Run the test class and you can see that there is no problem.

  • Modify userrealm The authentication method in Java queries users through the database
// authentication
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
    System.out.println("Yes===>authentication doGetAuthorizationInfo");

    UsernamePasswordToken userToken = (UsernamePasswordToken) authenticationToken;

     // User name and password authentication, retrieved from the database
    User user = userService.queryByName(userToken.getUsername());
    
    if (user == null)  // There is no such user (name)
       return null;  // An exception UnknownAccountException will be thrown

    // Password authentication, shiro do
    // Can be encrypted: MD5, MD5 salt value encryption
    return new SimpleAuthenticationInfo("",user.getPwd(),"");
}
  • Run the web project again and visit: http://localhost:8080/toLogin , you can still prompt relevant information by entering the wrong user name and password. At the same time, you can log in successfully by entering the user name and password in the user table in the database

  • OK, integrate MyBatis and Druid!

Request authorization

  • In shiroconfig Add authorization rules to methods in Java
// 3. Create ShiroFilterFactoryBean
@Bean
public ShiroFilterFactoryBean getShiroFilterFactoryBean(@Qualifier("securityManager") DefaultWebSecurityManager defaultWebSecurityManager) {
    ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
    // Set up security manager
    shiroFilterFactoryBean.setSecurityManager(defaultWebSecurityManager);

    // Add shiro's built-in filter
    /**
     * anon: Access without authentication
     * authc: Must be authenticated to access
     * user: You must have the remember me function to access
     * perms: You must have permission on a resource to access it
     * role: You must have a role permission to access
     */
    // Login interception
    Map<String, String> filterMap = new LinkedHashMap<>();

    // Authorization (to be placed first)
    filterMap.put("/user/add", "perms[user:add]");  // You must have add permission to access the add page
    filterMap.put("/user/update", "perms[user:update]"); // You must have update permission to access the update page

    // Intercept request
    filterMap.put("/user/*", "authc");  // Wildcards are supported

    shiroFilterFactoryBean.setFilterChainDefinitionMap(filterMap);

    // Set login request
    shiroFilterFactoryBean.setLoginUrl("/toLogin");

    return shiroFilterFactoryBean;
}
  • Test: run the following project to access: http://localhost:8080/toLogin , enter the correct user name and password (e.g. Le xiaoape, admin), log in, and then click the add or update link to find that it is not authorized,

  • Configure unauthorized pages:
  • In mycontroller Add a method in Java
@GetMapping("/unauthorized")
@ResponseBody
public String unauthorized() {
    return "You do not have permission to access this page";
}
  • Set the login request above before setting the unauthorized page
// Set unauthorized pages
shiroFilterFactoryBean.setUnauthorizedUrl("/unauthorized");
  • After repeating the above test, you can see that the user-defined unauthorized page is entered

  • Add permissions to users: in userrealm Authorization method in Java
// to grant authorization
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
    System.out.println("Yes===>to grant authorization doGetAuthorizationInfo");

    // Enter this method to add permissions to the user
    SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
    authorizationInfo.addStringPermission("user:add");

    return authorizationInfo;
}
  • Repeat the above test. You can see that you can access the add page after successful login

  • Get the permissions of the current user through the database:
  • First, modify the user table and add a column

  • Then use Easy Code to regenerate the entity class user Java (added a toString method) and userdao XML (added an SQL statement of queryByName)
/**
 * (User)Entity class
 */
public class User implements Serializable {
    private static final long serialVersionUID = 227972241159940478L;
    
    private Integer id;
    
    private String name;
    
    private String pwd;
    
    private String perms;


    public Integer getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getPwd() {
        return pwd;
    }

    public void setPwd(String pwd) {
        this.pwd = pwd;
    }

    public String getPerms() {
        return perms;
    }

    public void setPerms(String perms) {
        this.perms = perms;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", pwd='" + pwd + '\'' +
                ", perms='" + perms + '\'' +
                '}';
    }
}
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<mapper namespace="com.springboot.dao.UserDao">

    <resultMap type="com.springboot.entity.User" id="UserMap">
        <result property="id" column="id" jdbcType="INTEGER"/>
        <result property="name" column="name" jdbcType="VARCHAR"/>
        <result property="pwd" column="pwd" jdbcType="VARCHAR"/>
        <result property="perms" column="perms" jdbcType="VARCHAR"/>
    </resultMap>

    <!--Query single-->
    <select id="queryById" resultMap="UserMap">
        select
          id, name, pwd, perms
        from mybatis.user
        where id = #{id}
    </select>

    <select id="queryByName" parameterType="String" resultType="user">
        select
          id, name, pwd, perms
        from mybatis.user
        where name = #{name}
    </select>

    <!--Query specified row data-->
    <select id="queryAllByLimit" resultMap="UserMap">
        select
          id, name, pwd, perms
        from mybatis.user
        limit #{offset}, #{limit}
    </select>

    <!--Query by entity as filter criteria-->
    <select id="queryAll" resultMap="UserMap">
        select
          id, name, pwd, perms
        from mybatis.user
        <where>
            <if test="id != null">
                and id = #{id}
            </if>
            <if test="name != null and name != ''">
                and name = #{name}
            </if>
            <if test="pwd != null and pwd != ''">
                and pwd = #{pwd}
            </if>
            <if test="perms != null and perms != ''">
                and perms = #{perms}
            </if>
        </where>
    </select>

    <!--Add all columns-->
    <insert id="insert" keyProperty="id" useGeneratedKeys="true">
        insert into mybatis.user(name, pwd, perms)
        values (#{name}, #{pwd}, #{perms})
    </insert>

    <!--Modify data through primary key-->
    <update id="update">
        update mybatis.user
        <set>
            <if test="name != null and name != ''">
                name = #{name},
            </if>
            <if test="pwd != null and pwd != ''">
                pwd = #{pwd},
            </if>
            <if test="perms != null and perms != ''">
                perms = #{perms},
            </if>
        </set>
        where id = #{id}
    </update>

    <!--Delete by primary key-->
    <delete id="deleteById">
        delete from mybatis.user where id = #{id}
    </delete>

</mapper>
  • Modify userrealm Methods of authentication and authorization in Java
// to grant authorization
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
    System.out.println("Yes===>to grant authorization doGetAuthorizationInfo");

    // Enter this method to add permissions to the user
    SimpleAuthorizationInfo authorizationInfo = new SimpleAuthorizationInfo();
    //authorizationInfo.addStringPermission("user:add");

    // Get the current object
    Subject subject = SecurityUtils.getSubject();
    User currentUser = (User) subject.getPrincipal();  // Get the user object passed from the authentication method below

    // Add the permissions of the current user and get the permissions of the current user through the database
    authorizationInfo.addStringPermission(currentUser.getPerms());

    return authorizationInfo;
}

// authentication
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
    System.out.println("Yes===>authentication doGetAuthorizationInfo");

    UsernamePasswordToken userToken = (UsernamePasswordToken) authenticationToken;
    
    // User name and password authentication, retrieved from the database  
    User user = userService.queryByName(userToken.getUsername());

    if (user == null)  // There is no such user (name)
       return null;  // An exception UnknownAccountException will be thrown
    
    // Pass the user found in the database to the authorized method above
    return new SimpleAuthenticationInfo(user,user.getPwd(),"");
}
  • Test: access: http://localhost:8080/toLogin , log in with the user name and password in the user table in the database. You can see that only users with certain permissions can access the pages they can access. Test OK!
  • Request authorization completed!

shiro integrates thymeleaf

Official website documents: https://github.com/theborakompanioni/thymeleaf-extras-shiro

  • In POM Add integration dependency to XML
<dependency>
    <groupId>com.github.theborakompanioni</groupId>
    <artifactId>thymeleaf-extras-shiro</artifactId>
    <version>2.0.0</version>
</dependency>
  • In shiroconfig Integrating shiro and thymeleaf in Java
// Integrate ShiroDialect: used to integrate shiro and thymeleaf
@Bean
public ShiroDialect getShiroDialect(){
    return new ShiroDialect();
}
  • In index Add judgment to HTML
<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org" xmlns:shiro="http://www.pollix.at/thymeleaf/shiro">
<head>
  <meta charset="UTF-8">
  <title>Title</title>
</head>
<body>
  <h1>home page</h1>
  <p th:text="${msg}"></p>

  <p shiro:notAuthenticated="">
    <a th:href="@{/toLogin}">Sign in</a>
  </p>

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

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

</body>
</html>
  • Rerun the project to access: http://localhost:8080/ , only login is displayed when there is no login

  • Click log in and log in with Le xiaoape's account. If you only have add permission, only the add page will be displayed

  • Log in with a beta account and only display the update page if you have update permission

  • OK, integration is complete!

Keywords: Java Mybatis Shiro Spring Boot Thymeleaf

Added by Fazer on Thu, 20 Jan 2022 23:52:53 +0200