SpringBoot整合Shiro学习(下)

SpringBoot整合Shiro(下)

基于【编程不良人】2020最新版Shiro教程,整合SpringBoot项目实战教程

哔哩哔哩链接:https://www.bilibili.com/video/BV1uz4y197Zm?p=1

在中篇中我们已经了解到shiro对jsp页面有很好的集成,但是与thymeleaf却没有,需要我们引入相关的依赖和配置才可以。接下来我们将学习shiro与thymeleaf的整合

九、Shiro与thymeleaf整合

1.新建springboot项目

此处以ideal为例,我们新建一个springboot项目,

image-20211119185045821

配置项目信息,

image-20211119185131879

引入依赖,

image-20211119185318968

对项目进行命名等配置,

image-20211121140706694

2.引入依赖

创建好项目后,我们需要引入更多依赖,我们打开pom.xml文件,具体代码如下:

<?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 https://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <parent>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-parent</artifactId>
        <version>2.3.2.RELEASE</version>
        <relativePath/> <!-- lookup parent from repository -->
    </parent>
    <groupId>com.example</groupId>
    <artifactId>demo</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>demo</name>
    <description>Demo project for Spring Boot</description>
    <properties>
        <java.version>1.8</java.version>
    </properties>
    <dependencies>
        <!-- thymeleaf -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
        <!-- shiro与thymeleaf的扩展依赖 -->
        <dependency>
            <groupId>com.github.theborakompanioni</groupId>
            <artifactId>thymeleaf-extras-shiro</artifactId>
            <version>2.0.0</version>
        </dependency>
        <!-- 引入shiro整合Springboot依赖 -->
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-spring-boot-starter</artifactId>
            <version>1.5.3</version>
        </dependency>
        <!-- 引入shiro和ehcache(当我们的缓存实现是redis时可以去掉此依赖) -->
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-ehcache</artifactId>
            <version>1.5.3</version>
        </dependency>
        <!-- redis整合springboot -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-data-redis</artifactId>
        </dependency>
        <!-- fastjson -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>1.2.70</version>
        </dependency>
        <!-- web依赖 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!-- mybatis相关依赖 -->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.1.2</version>
        </dependency>
        <!-- mysql连接java驱动 -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.23</version>
        </dependency>
        <!-- druid数据库连接池 -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.19</version>
        </dependency>

        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <scope>runtime</scope>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <scope>test</scope>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <configuration>
                    <excludes>
                        <exclude>
                            <groupId>org.projectlombok</groupId>
                            <artifactId>lombok</artifactId>
                        </exclude>
                    </excludes>
                </configuration>
            </plugin>
        </plugins>
    </build>

</project>

3.书写项目配置文件

我们很多配置都是和之前一样的,此处只需要将jsp的配置改为thymeleaf的配置即可,具体如下:

server.port=8080
server.servlet.context-path=/shiro
spring.application.name=shiro
# 关闭thymeleaf的缓存,方便测试,在项目上线时需要改为true
spring.thymeleaf.cache=false
# thymeleaf的很多配置都有默认值,基本上不用我们做很多配置
spring.thymeleaf.suffix=.html
spring.thymeleaf.prefix=classpath:/templates/

spring.datasource.type=com.alibaba.druid.pool.DruidDataSource
spring.datasource.driver-class-name=com.mysql.cj.jdbc.Driver
spring.datasource.url=jdbc:mysql://localhost:3306/shiro?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
spring.datasource.username=root
spring.datasource.password=123456

mybatis.type-aliases-package=com.example.demo.entity
mybatis.mapper-locations=classpath:mapper/*.xml


logging.level.com.example.demo.dao=debug

4.引入之前的包

由于我们的业务都是一样的,我们将之前的项目中的代码目录复制过来更改一下即可,我们需要更改的位置如下:

1.打开UserController.java,由之前的直接跳转jsp页面更改为通过控制器进行跳转,因为thymeleaf不能直接访问视图,需要通过控制器进行访问,如果我们直接访问界面,是不能由thymeleaf进行解析的。

image-20211121152152832

具体代码如下:

package com.example.demo.controller;

import com.example.demo.cache.FastJson2JsonRedisSerializer;
import com.example.demo.entity.User;
import com.example.demo.service.UserService;
import com.example.demo.utils.ApplicationContextUtils;
import com.example.demo.utils.VerifyCodeUtils;
import com.fasterxml.jackson.annotation.JsonAutoDetect;
import com.fasterxml.jackson.annotation.JsonTypeInfo;
import com.fasterxml.jackson.annotation.PropertyAccessor;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.jsontype.impl.LaissezFaireSubTypeValidator;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.serializer.StringRedisSerializer;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;

@Controller
@RequestMapping("user")
public class UserController {

    @Autowired
    private UserService userService;

    /* 跳转到login.html页面 */
    @RequestMapping("loginView")
    public String toLogin(){
        return "login";
    }

    /* 跳转到register.html页面 */
    @RequestMapping("registerView")
    public String toRegister(){
        return "register";
    }

    /* 跳转到register.html页面 */
    @RequestMapping("indexView")
    public String toIndex(){
        return "index";
    }

    /**
     * 测试我们自定义的序列化方式
     */
    @RequestMapping("test")
    @ResponseBody
    public String test() {
        RedisTemplate redisTemplate = (RedisTemplate) ApplicationContextUtils.getBean("redisTemplate");
        System.out.println(redisTemplate);
        /* 序列化key的序列化方式为string类型的序列化方式 */
        redisTemplate.setKeySerializer(new StringRedisSerializer());
        // 使用Jackson2JsonRedisSerializer来序列化和反序列化redis的value值
        // Jackson2JsonRedisSerializer serializer = new Jackson2JsonRedisSerializer(Object.class);
        // 使用Fastjson2JsonRedisSerializer来序列化和反序列化redis的value值
        FastJson2JsonRedisSerializer serializer = new FastJson2JsonRedisSerializer(Object.class);

        // Jackson之ObjectMapper对象的使用: https://blog.csdn.net/qq_41834086/article/details/111152470
        ObjectMapper mapper = new ObjectMapper();
        // ALL:此伪类型表明所有访问器都受到影响。ANY:所有类型的访问修饰符都是可接受的,从私有到公有。
        mapper.setVisibility(PropertyAccessor.ALL, JsonAutoDetect.Visibility.ANY);
        mapper.activateDefaultTyping(LaissezFaireSubTypeValidator.instance, ObjectMapper.DefaultTyping.NON_FINAL, JsonTypeInfo.As.PROPERTY);
        serializer.setObjectMapper(mapper);
        // 使用Jackson2JsonRedisSerializerr来序列化和反序列化redis的value值
        redisTemplate.setValueSerializer(serializer);
        /* 查询tom的数据 */
        User tom = userService.findByUserName("tom");
        redisTemplate.opsForValue().set("123",tom);
        return "ok";
    }

    /**
     * 退出登录
     */
    @RequestMapping("logout")
    public String logout() {
        Subject subject = SecurityUtils.getSubject();
        subject.logout();//退出用户
        return "redirect:/user/loginView";
    }

    /**
     * 用来处理身份认证
     * @param username
     * @param password
     * @return
     */
    @RequestMapping("login")
    public String login(String username, String password, String code, HttpSession session) {
        //比较验证码
        String codes = (String) session.getAttribute("code");
        try {
            /* 在web环境中,只要我们在ShiroConfig配置中创建了安全管理器,shiro就会自动给SecurityUtils注入web的安全管理器,
             即注入DefaultWebSecurityManager*/
            // 获取主体对象
            if (codes.equalsIgnoreCase(code)) {
                Subject subject = SecurityUtils.getSubject();
                // 在认证过程中使用subject.login进行认证, UsernamePasswordToken将用户名密码封装为token
                subject.login(new UsernamePasswordToken(username, password));
                return "redirect:/user/indexView";
            }else {
                throw new RuntimeException("验证码错误!");
            }
        } catch (UnknownAccountException e) {
            e.printStackTrace();
            System.out.println("用户名错误!");
        } catch (IncorrectCredentialsException e) {
            e.printStackTrace();
            System.out.println("密码错误!");
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println(e.getMessage());
        }
        return "redirect:/user/loginView";
    }

    /**
     * 用户注册
     */
    @RequestMapping("register")
    public String register(User user) {
        try {
            userService.register(user);
            return "redirect:/user/loginView";
        }catch (Exception e){
            e.printStackTrace();
            return "redirect:/user/registerView";
        }
    }

    /* 基于授权的代码方式测试 */
    @RequestMapping("save")
    public String save(){
        //基于角色
        //获取主体对象
        Subject subject = SecurityUtils.getSubject();
        //代码方式
        if (subject.hasRole("admin")) {
            System.out.println("有admin角色!");
        }else{
            System.out.println("无admin角色!");
        }
        //基于权限字符串
        /*
        * isPermitted() 方法判断这个登录的用户是否具有参数字符串所表示的权限,返回一个 boolean 类型的值。
        * checkPermission() 和 isPermitted() 方法的功能是类似的,区别在于如果这个登录的用户不具有参数字符串所表示的权限时,程序将抛出异常。
        * 类似地,hasRole() 和 checkRole() 方法也有类似的作用,在这里就不多做解释了。
        * */
        if (subject.isPermittedAll("user:*")){
            System.out.println("拥有user:*权限");
        }else {
            System.out.println("没有user:*权限");
        }
        return "redirect:/user/indexView";
    }

    /* 基于授权的注解方式测试 */
    @RequestMapping("save2")
    // @RequiresRoles(value={"admin","user"})//用来判断角色,这里表示同时具有 admin user 角色才能进行此方法
    // 用来判断权限字符串,这里表示user:update:01才能进入此方法(如果是user:*:*(可以简写为user:*)或者*:*:*(全部角色)也可进入此方法)
    @RequiresPermissions("user:update:01")
    public String save2(){
        System.out.println("进入了此方法");
        return "redirect:/user/indexView";
    }

    /* 生成验证码 */
    @RequestMapping("getImage")
    public void getImage(HttpSession session, HttpServletResponse response) throws IOException {
        // 生成4位验证码
        String code = VerifyCodeUtils.generateVerifyCode(4);
        // 验证码放入session
        session.setAttribute("code",code);
        // 以response响应流的形式将验证码存入图片
        ServletOutputStream os = response.getOutputStream(); // 拿到响应流
        // 给响应流设置响应类型
        response.setContentType("image/png");
        VerifyCodeUtils.outputImage(220, 60, os, code);
    }
}

2.修改shiro配置

我们打开ShiroConfig.java文件,放行UserController.java更改后的请求和界面

image-20211121152616881

具体代码如下:

package com.example.demo.config;

import at.pollux.thymeleaf.shiro.dialect.ShiroDialect;
import com.example.demo.cache.RedisCacheManager;
import com.example.demo.realm.CustomerRealm;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.realm.Realm;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

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

/**
 * 用来整合shiro框架相关的配置类
 */
@Configuration
public class ShiroConfig {
    // 1.创建shiroFilter , 负责拦截所有请求
    @Bean
    public ShiroFilterFactoryBean getShiroFilterFactoryBean(DefaultWebSecurityManager defaultWebSecurityManager){
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        // 给filter设置安全管理器
        shiroFilterFactoryBean.setSecurityManager(defaultWebSecurityManager);
        // 配置系统受限资源 和 配置系统公共资源
        Map<String,String> map = new HashMap<String,String>();
        // key为系统资源的路径,anon 表示设置为公共资源,它是一个filter
        map.put("/user/login","anon");// 放行登录请求
        map.put("/user/register","anon");// 放行注册请求
        map.put("/user/test","anon");// 测试自定义的序列化方式
        map.put("/user/getImage","anon");// 验证码请求放行
        map.put("/user/loginView","anon");// 放行登录界面跳转请求
        map.put("/user/registerView","anon");// 放行注册界面跳转请求
        map.put("/login.html","anon");// 放行注册界面
        map.put("/register.html","anon");// 放行注册界面
        map.put("/user/indexView","authc"); // authc 表示请求这个资源需要认证和授权,它是一个filter
        map.put("/**","authc"); // 表示请求所有资源都需要认证和授权
        // 默认认证界面路径---当认证不通过时跳转(我们可以自定义,不写默认就是它(/login.jsp))
        shiroFilterFactoryBean.setLoginUrl("/user/loginView");
        shiroFilterFactoryBean.setFilterChainDefinitionMap(map);
        return shiroFilterFactoryBean;
    }

    // 2.创建安全管理器,此处使用DefaultWebSecurityManager,我们之前使用的DefaultSecurityManager不具有web容器的特性
    @Bean
    public DefaultWebSecurityManager getDefaultWebSecurityManager(Realm realm){
        DefaultWebSecurityManager defaultWebSecurityManager = new DefaultWebSecurityManager();
        //给安全管理器设置
        defaultWebSecurityManager.setRealm(realm);
        return defaultWebSecurityManager;
    }

    // 3.创建自定义realm
    @Bean("realm")
    public Realm getRealm(){
        CustomerRealm customerRealm = new CustomerRealm();
        // 设置hashed凭证匹配器
        HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher();
        // 设置md5加密
        credentialsMatcher.setHashAlgorithmName("md5");
        // 设置散列次数
        credentialsMatcher.setHashIterations(1024);
        customerRealm.setCredentialsMatcher(credentialsMatcher);
        // 开启缓存管理器
        customerRealm.setCacheManager(new RedisCacheManager()); // 使用自定义的RedisCacheManager缓存的实现
        customerRealm.setCachingEnabled(true);// 开启全局的缓存管理
        customerRealm.setAuthenticationCachingEnabled(true);// 开启认证的缓存管理
        // 给认证的缓存在内存中起名字,不写则默认为“包名+authenticationCache“,如此处为com.example.demo.realm.CustomerRealm.authenticationCache
        customerRealm.setAuthenticationCacheName("authenticationCache");
        customerRealm.setAuthorizationCachingEnabled(true);// 开启授权的缓存管理
        // 给授权的缓存在内存中起名字,不写则默认为“包名+authorizationCache“,如此处为com.example.demo.realm.CustomerRealm.authorizationCache
        customerRealm.setAuthorizationCacheName("authorizationCache");
        return customerRealm;
    }

    /* 加入shiro的方言,解决shiro与thymeleaf整合页面中的标签不生效的原因 */
    @Bean(name = "shiroDialect")
    public ShiroDialect shiroDialect(){
        return new ShiroDialect();
    }
}

3.将jsp页面更改为html页面,此处需要注意的是我们需要引入thymeleaf和shiro的命名空间,即

<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org"
      xmlns:shiro="http://www.pollix.at/thymeleaf/shiro">

此处我们先扩展shiro与thymeleaf整合常见权限控制标签使用:

5.常见权限控制标签使用

<!-- 验证当前用户是否为“访客”,即未认证(包含未记住)的用户。 -->
<p shiro:guest="">Please <a href="login.html">login</a></p>


<!-- 认证通过或已记住的用户。 -->
<p shiro:user="">
    Welcome back John! Not John? Click <a href="login.html">here</a> to login.
</p>

<!-- 已认证通过的用户。不包含已记住的用户,这是与user标签的区别所在。 -->
<p shiro:authenticated="">
    Hello, <span shiro:principal=""></span>, how are you today?
</p>
<a shiro:authenticated="" href="updateAccount.html">Update your contact information</a>

<!-- 输出当前用户信息,通常为登录帐号信息。 -->
<p>Hello, <shiro:principal/>, how are you today?</p>


<!-- 未认证通过用户,与authenticated标签相对应。与guest标签的区别是,该标签包含已记住用户。 -->
<p shiro:notAuthenticated="">
    Please <a href="login.html">login</a> in order to update your credit card information.
</p>

<!-- 验证当前用户是否属于该角色。 -->
<a shiro:hasRole="admin" href="admin.html">Administer the system</a><!-- 拥有该角色 -->

<!-- 与hasRole标签逻辑相反,当用户不属于该角色时验证通过。 -->
<p shiro:lacksRole="developer"><!-- 没有该角色 -->
    Sorry, you are not allowed to developer the system.
</p>

<!-- 验证当前用户是否属于以下所有角色。 -->
<p shiro:hasAllRoles="developer, 2"><!-- 角色与判断 -->
    You are a developer and a admin.
</p>

<!-- 验证当前用户是否属于以下任意一个角色。  -->
<p shiro:hasAnyRoles="admin, vip, developer,1"><!-- 角色或判断 -->
    You are a admin, vip, or developer.
</p>

<!--验证当前用户是否拥有指定权限。  -->
<a shiro:hasPermission="userInfo:add" href="createUser.html">添加用户</a><!-- 拥有权限 -->

<!-- 与hasPermission标签逻辑相反,当前用户没有制定权限时,验证通过。 -->
<p shiro:lacksPermission="userInfo:del"><!-- 没有权限 -->
    Sorry, you are not allowed to delete user accounts.
</p>

<!-- 验证当前用户是否拥有以下所有角色。 -->
<p shiro:hasAllPermissions="userInfo:view, userInfo:add"><!-- 权限与判断 -->
    You can see or add users.
</p>

<!-- 验证当前用户是否拥有以下任意一个权限。  -->
<p shiro:hasAnyPermissions="userInfo:view, userInfo:del"><!-- 权限或判断 -->
    You can see or delete users.
</p>
<a shiro:hasPermission="pp" href="createUser.html">Create a new User</a>


了解了之后,我们书写代码,具体代码如下:

image-20211121151523391

index.html

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" xmlns:th="http://www.thymeleaf.org"
      xmlns:shiro="http://www.pollix.at/thymeleaf/shiro">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>主页</title>
</head>
<body>
<h1>系统主页</h1>
<!-- 输出当前用户信息,通常为登录帐号信息。 -->
<p>Hello, <shiro:principal/>, how are you today?</p>
<a th:href="@{/user/logout}">退出登录</a>
<ul>
    <shiro:hasAnyRoles name="user_manager,admin,addinfo_manager">
        <li><a href="">用户管理</a>
            <ul>
                <shiro:hasPermission name="user:add:*">
                    <li><a href="">添加</a></li>
                </shiro:hasPermission>
                <shiro:hasPermission name="user:delete:*">
                    <li><a href="">删除</a></li>
                </shiro:hasPermission>
                <shiro:hasPermission name="user:update:*">
                    <li><a href="">修改</a></li>
                </shiro:hasPermission>
                <shiro:hasPermission name="user:find:*">
                    <li><a href="">查询</a></li>
                </shiro:hasPermission>
            </ul>
        </li>
    </shiro:hasAnyRoles>
    <shiro:hasAnyRoles name="order_manager,admin,addinfo_manager">
        <li><a href="">订单管理</a></li>
        <ul>
            <shiro:hasPermission name="order:add:*">
                <li><a href="">添加</a></li>
            </shiro:hasPermission>
            <shiro:hasPermission name="order:delete:*">
                <li><a href="">删除</a></li>
            </shiro:hasPermission>
            <shiro:hasPermission name="order:update:*">
                <li><a href="">修改</a></li>
            </shiro:hasPermission>
            <shiro:hasPermission name="order:find:*">
                <li><a href="">查询</a></li>
            </shiro:hasPermission>
        </ul>
    </shiro:hasAnyRoles>
    <shiro:hasRole name="admin">
        <li><a href="">商品管理</a></li>
        <li><a href="">物流管理</a></li>
    </shiro:hasRole>

    <shiro:hasRole name="user">
        <li><a href="">仅普通用户可见</a></li>
        <li><a href="">公共资源</a></li>
    </shiro:hasRole>
</ul>
</body>
</html>

login.html

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" 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>登录界面</h1>
<form th:action="@{/user/login}" method="post">
    用户名:<input type="text" name="username"> <br/>
    密 码 : <input type="text" name="password"> <br>
    请输入验证码: <input type="text" name="code"><img th:src="@{/user/getImage}" alt=""><br>
    <input type="submit" value="登录"><br>
    <a th:href="@{/user/registerView}">前往注册</a>
</form>
</body>
</html>


register.html

<!DOCTYPE html>
<html xmlns="http://www.w3.org/1999/xhtml" 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>注册界面</h1>
<form th:action="@{/user/register}" method="post">
    用户名:<input type="text" name="username"> <br/>
    密 码 : <input type="text" name="password"> <br/>
    <input type="submit" value="立即注册"><br/>
    <a th:href="@{/user/loginView}">返回登录</a>
</form>
</body>
</html>

6.加入shiro的方言配置

  • 页面标签不起作用一定要记住加入方言处理

  • 之后我们还要引入shiro的方言配置,因为thymeleaf与shiro结合后默认是没有解析shiro的方言的,所以页面上的shiro页面标签不起作用,我们打开ShiroConfig.java文件,加入以下代码,

    image-20211121153303165

/* 加入shiro的方言,解决shiro与thymeleaf整合页面中的标签不生效的原因 */
@Bean(name = "shiroDialect")
public ShiroDialect shiroDialect(){
    return new ShiroDialect();
}

重启项目,进行登录,登录成功。

image-20211121153402980

源码获取

至此,我们的SpringBoot整合Shiro学习(下)就讲解完成了。源码和数据库文件可以通过关注我的微信公众号 我爱学习呀嘻嘻 ,回复关键字shiro集成进行获取哦。

SpringBoot整合Shiro学习(上):Shiro基础知识

SpringBoot整合Shiro学习(中):Shiro与Jsp页面整合
image-20211108230322493

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值