Springboot整合Shiro框架入门

1、快速开始demo

来到shiro的官网:shiro官方网站
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
下载官方在git仓库上提供的源码,下载后解压:
在这里插入图片描述
在这里插入图片描述
官方提供了在多种场景下使用的demo,等一下会用到sample里面的东西。下面直接按官方推荐的10分钟入门demo进行测试。

创建一个总的父工程shiro-demo,在父工程下创建一个子模块shiro-demo-01,如下:
在这里插入图片描述
父工程下什么都没有,src源目录删掉了,pom.xml也是空的:
在这里插入图片描述
父工程pom什么依赖也没有,只包含一个子module。

子模块shiro-demo-01目录如下:
在这里插入图片描述
总共只有4个东西,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 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <parent>
        <artifactId>shiro-demo-parent</artifactId>
        <groupId>com.ycz</groupId>
        <version>1.0-SNAPSHOT</version>
    </parent>
    <modelVersion>4.0.0</modelVersion>

    <artifactId>shiro-demo-01</artifactId>

    <dependencies>

        <!-- shiro核心依赖 -->
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-core</artifactId>
            <version>1.4.1</version>
        </dependency>

        <!-- slf4j日志依赖 -->
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>jcl-over-slf4j</artifactId>
            <version>1.7.21</version>
        </dependency>

        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
            <version>1.7.21</version>
        </dependency>

        <!-- log4j日志依赖 -->
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>
    </dependencies>

</project>

log4j.properties和shiro.ini都是从sample目录里的quickstart里面直接复制粘贴过来的。
在这里插入图片描述
日志配置文件log4j.properties内容如下:

log4j.rootLogger=INFO, stdout

log4j.appender.stdout=org.apache.log4j.ConsoleAppender
log4j.appender.stdout.layout=org.apache.log4j.PatternLayout
log4j.appender.stdout.layout.ConversionPattern=%d %p [%c] - %m %n

# General Apache libraries
log4j.logger.org.apache=WARN

# Spring
log4j.logger.org.springframework=WARN

# Default Shiro logging
log4j.logger.org.apache.shiro=INFO

# Disable verbose logging
log4j.logger.org.apache.shiro.util.ThreadContext=WARN
log4j.logger.org.apache.shiro.cache.ehcache.EhCache=WARN

shiro配置文件shiro.ini内容如下:


# -----------------------------------------------------------------------------
# Users and their assigned roles
#
# Each line conforms to the format defined in the
# org.apache.shiro.realm.text.TextConfigurationRealm#setUserDefinitions JavaDoc
# -----------------------------------------------------------------------------
[users]
# user 'root' with password 'secret' and the 'admin' role
root = secret, admin
# user 'guest' with the password 'guest' and the 'guest' role
guest = guest, guest
# user 'presidentskroob' with password '12345' ("That's the same combination on
# my luggage!!!" ;)), and role 'president'
presidentskroob = 12345, president
# user 'darkhelmet' with password 'ludicrousspeed' and roles 'darklord' and 'schwartz'
darkhelmet = ludicrousspeed, darklord, schwartz
# user 'lonestarr' with password 'vespa' and roles 'goodguy' and 'schwartz'
lonestarr = vespa, goodguy, schwartz

# -----------------------------------------------------------------------------
# Roles with assigned permissions
# 
# Each line conforms to the format defined in the
# org.apache.shiro.realm.text.TextConfigurationRealm#setRoleDefinitions JavaDoc
# -----------------------------------------------------------------------------
[roles]
# 'admin' role has all permissions, indicated by the wildcard '*'
admin = *
# The 'schwartz' role can do anything (*) with any lightsaber:
schwartz = lightsaber:*
# The 'goodguy' role is allowed to 'drive' (action) the winnebago (type) with
# license plate 'eagle5' (instance specific id)
goodguy = winnebago:drive:eagle5

src源目录下的Qucikstart也是从quickstart里拷出来的,内容如下:

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.config.IniSecurityManagerFactory;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.util.Factory;
import org.apache.shiro.mgt.SecurityManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * @Description
 * @ClassName Quickstart
 * @Author yanchengzhi
 * @date 2021.09.24 13:31
 */
public class Quickstart {

    private static final transient Logger log = LoggerFactory.getLogger(Quickstart.class);


    public static void main(String[] args) {


        Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro.ini");
        SecurityManager securityManager = factory.getInstance();
        SecurityUtils.setSecurityManager(securityManager);

        // 获取当前用户对象Subject
        Subject currentUser = SecurityUtils.getSubject();

        // 通过当前用户获取Session对象
        Session session = currentUser.getSession();
        session.setAttribute("someKey", "aValue");
        String value = (String) session.getAttribute("someKey");
        if (value.equals("aValue")) {
            log.info("Shiro==Session===> [" + value + "]");
        }

        // 判断当前用户是否认证
        if (!currentUser.isAuthenticated()) {
            // 登录名和密码封装为token
            UsernamePasswordToken token = new UsernamePasswordToken("lonestarr", "vespa");
            // 是否使用记住我
            token.setRememberMe(true);
            try {
                // 执行登录
                currentUser.login(token);
            } catch (UnknownAccountException uae) {
                log.info("There is no user with username of " + token.getPrincipal());
            } catch (IncorrectCredentialsException ice) {
                log.info("Password for account " + token.getPrincipal() + " was incorrect!");
            } catch (LockedAccountException lae) {
                log.info("The account for username " + token.getPrincipal() + " is locked.  " +
                        "Please contact your administrator to unlock it.");
            }
            // ... catch more exceptions here (maybe custom ones specific to your application?
            catch (AuthenticationException ae) {
                //unexpected condition?  error?
            }
        }

        //getPrincipal方法获取用户认证信息
        log.info("User [" + currentUser.getPrincipal() + "] logged in successfully.");

        //test a role:
        if (currentUser.hasRole("schwartz")) {
            log.info("May the Schwartz be with you!");
        } else {
            log.info("Hello, mere mortal.");
        }

        //test a typed permission (not instance-level)
        if (currentUser.isPermitted("lightsaber:wield")) {
            log.info("You may use a lightsaber ring.  Use it wisely.");
        } else {
            log.info("Sorry, lightsaber rings are for schwartz masters only.");
        }

        //a (very powerful) Instance Level permission:
        if (currentUser.isPermitted("winnebago:drive:eagle5")) {
            log.info("You are permitted to 'drive' the winnebago with license plate (id) 'eagle5'.  " +
                    "Here are the keys - have fun!");
        } else {
            log.info("Sorry, you aren't allowed to drive the 'eagle5' winnebago!");
        }

        //登出
        currentUser.logout();

        System.exit(0);
    }
}

运行main方法:
在这里插入图片描述
控制台打印的日志信息如上面,到这里快速开始的demo就运行成功了。

2、Springboot集成Shiro

下面测试在Springboot中集成Shiro框架,先进行环境的搭建。

2.1、环境搭建

在父工程shiro-demo下创建子模块shiro-boot,目录如下:
在这里插入图片描述
(1)pom依赖

<?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>
    <groupId>com.ycz</groupId>
    <artifactId>shiro-boot</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <name>shiro-boot</name>
    <description>Demo project for Spring Boot</description>

    <properties>
        <java.version>1.8</java.version>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <spring-boot.version>2.3.7.RELEASE</spring-boot.version>
    </properties>

    <dependencies>
        <!-- thymeleaf模板依赖 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-thymeleaf</artifactId>
        </dependency>
        <!-- web模块依赖 -->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
        </dependency>
        <!--热部署-->
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-devtools</artifactId>
            <optional>true</optional>
            <scope>true</scope>
        </dependency>
        <!-- shiro和spring的整合依赖 -->
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-spring</artifactId>
            <version>1.7.1</version>
        </dependency>
        <!-- test模块依赖 -->
        <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>

    <dependencyManagement>
        <dependencies>
            <dependency>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-dependencies</artifactId>
                <version>${spring-boot.version}</version>
                <type>pom</type>
                <scope>import</scope>
            </dependency>
        </dependencies>
    </dependencyManagement>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.8.1</version>
                <configuration>
                    <source>1.8</source>
                    <target>1.8</target>
                    <encoding>UTF-8</encoding>
                </configuration>
            </plugin>
            <plugin>
                <groupId>org.springframework.boot</groupId>
                <artifactId>spring-boot-maven-plugin</artifactId>
                <version>2.3.7.RELEASE</version>
                <configuration>
                    <mainClass>com.ycz.shiroboot.ShiroBootApplication</mainClass>
                </configuration>
                <executions>
                    <execution>
                        <id>repackage</id>
                        <goals>
                            <goal>repackage</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>

</project>

(2)application.properties配置

# 应用名称
spring.application.name=shiro-boot
# 应用服务 WEB 访问端口
server.port=8080
# THYMELEAF (ThymeleafAutoConfiguration)
# 开启模板缓存(默认值: true )
spring.thymeleaf.cache=false
# 检查模板是否存在,然后再呈现
spring.thymeleaf.check-template=true
# 检查模板位置是否正确(默认值 :true )
spring.thymeleaf.check-template-location=true
#Content-Type 的值(默认值: text/html )
spring.thymeleaf.content-type=text/html
# 开启 MVC Thymeleaf 视图解析(默认值: true )
spring.thymeleaf.enabled=true
# 模板编码
spring.thymeleaf.encoding=UTF-8
# 要被排除在解析之外的视图名称列表,⽤逗号分隔
spring.thymeleaf.excluded-view-names=
# 要运⽤于模板之上的模板模式。另⻅ StandardTemplate-ModeHandlers( 默认值: HTML5)
spring.thymeleaf.mode=HTML5
# 在构建 URL 时添加到视图名称前的前缀(默认值: classpath:/templates/ )
spring.thymeleaf.prefix=classpath:/templates/
# 在构建 URL 时添加到视图名称后的后缀(默认值: .html )
spring.thymeleaf.suffix=.html

(3)shiro配置

在config包下是关于Shiro的关键配置:
在这里插入图片描述
先自定义所需的Realm类,只需继承AuthorizingRealm类即可,内容如下:

package com.ycz.shiroboot.config;

import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;

/**
 * @Description 自定义Realm,继承AuthorizingRealm类,重写认证和授权方法
 * @ClassName UserRealm
 * @Author yanchengzhi
 * @date 2021.09.25 15:36
 */
public class UserRealm extends AuthorizingRealm {

    // 授权
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        System.out.println("进入授权方法!");
        return null;
    }

    // 认证
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        System.out.println("进入认证方法!");
        return null;
    }
}

再配置ShiroConfig类,这个类主要是用来向Spring容器中注入bean的,内容如下:

package com.ycz.shiroboot.config;

import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

/**
 * @Description Shiro的配置类
 * @ClassName ShiroConfig
 * @Author yanchengzhi
 * @date 2021.09.25 15:35
 */
@Configuration
public class ShiroConfig {

    /*
    * @description: 注入UserRealm的bean
    * @param: []
    * @return: com.ycz.shiroboot.config.UserRealm
    * @author: yanchengzhi
    * @date: 2021/9/25 15:42
    */
    @Bean
    public UserRealm userRealm() {
        return new UserRealm();
    }

    /*
     * @description: 注入DefaultWebSecurityManager的bean,需要依赖定义的UserRealm对象
     * @param: [userRealm]
     * @return: org.apache.shiro.web.mgt.DefaultWebSecurityManager
     * @author: yanchengzhi
     * @date: 2021/9/25 15:47
     */
    @Bean(name = "securityManager")
    public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm) {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        // 关联realm
        securityManager.setRealm(userRealm);
        return securityManager;
    }

    /*
    * @description: 注入ShiroFilterFactoryBean的bean,需要依赖DefaultWebSecurityManager对象
    * @param: [defaultWebSecurityManager]
    * @return: org.apache.shiro.spring.web.ShiroFilterFactoryBean
    * @author: yanchengzhi
    * @date: 2021/9/25 15:52
    */
    @Bean
    public ShiroFilterFactoryBean getShiroFilterFactoryBean(
            @Qualifier("securityManager") DefaultWebSecurityManager defaultWebSecurityManager) {
        // 设置安全管理器
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        shiroFilterFactoryBean.setSecurityManager(defaultWebSecurityManager);
        return shiroFilterFactoryBean;
    }

}

(4)准备页面

准备所需的几个页面,目录层次如下:
在这里插入图片描述
index.html直接在templates目录下,而add.html和edit.html在user目录下。

index.html内容如下:

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>index页面</title>
</head>
<body>
    <h1>欢迎来到首页!</h1>
    <h2 style="color: red;" th:text="${key}"></h2>
    <a th:href="@{/user/add}">添加用户</a> | <a th:href="@{/user/edit}">修改用户</a>
</body>
</html>

add.html内容如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>用户添加页面</title>
</head>
<body>
   <h1>添加页面</h1>
</body>
</html>

edit.html内容如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>用户修改页面</title>
</head>
<body>
   <h1>修改页面</h1>
</body>
</html>

(5)控制器

在controller包下创建一个TestController类控制器:
在这里插入图片描述
具体内容如下:

package com.ycz.shiroboot.controller;

import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.RequestMapping;

/**
 * @Description
 * @ClassName TestController
 * @Author yanchengzhi
 * @date 2021.09.25 15:10
 */
@Controller
@RequestMapping("/")
public class TestController {

    /*
    * @description: 默认跳转
    * @param: [model]
    * @return: java.lang.String
    * @author: yanchengzhi
    * @date: 2021/9/25 16:20
    */
    @RequestMapping("")
    public String toIndexPage(Model model) {
        model.addAttribute("key","Shiro安全框架");
        return "index";
    }

    /*
    * @description: 跳往添加页面
    * @param: []
    * @return: java.lang.String
    * @author: yanchengzhi
    * @date: 2021/9/25 16:21
    */
    @RequestMapping("/user/add")
    public String toAddPage() {
        return "/user/add";
    }
    
    /*
    * @description: 跳往编辑修改页面
    * @param: []
    * @return: java.lang.String
    * @author: yanchengzhi
    * @date: 2021/9/25 16:22
    */
    @RequestMapping("/user/edit")
    public String toEditPage() {
        return "/user/edit";
    }
}

(6)测试

启动Springboot项目,访问:http://localhost:8080/。
在这里插入图片描述
成功跳转到了默认页面index.html,点击添加用户:
在这里插入图片描述
在这里插入图片描述
跳转到了添加页面,再点击修改用户:
在这里插入图片描述
在这里插入图片描述
跳转到了修改页面。OK,到这里环境就搭建完成了,先保证项目能够跑得起来。下面将进一步的配置和测试。

2.2、shiro的拦截

shiro中请求的拦截是通过ShiroFilterFactoryBean对象来完成的,刚才其实在ShiroConfig中已经配置该类型的bean了,只不过有的配置内容没有加进去。下面在之前的基础上添加一些配置:

    @Bean
    public ShiroFilterFactoryBean getShiroFilterFactoryBean(
            @Qualifier("securityManager") DefaultWebSecurityManager defaultWebSecurityManager) {
        // 设置安全管理器
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        shiroFilterFactoryBean.setSecurityManager(defaultWebSecurityManager);
        // 添加Shiro常用的过滤器
        /**
         *  常用过滤器如下:
         *  anon:无需认证即可访问
         *  authc:必须经过认证才能访问
         *  user:使用记住我后可访问
         *  perms:拥有某个资源的权限才可访问
         *  role:拥有某个角色才可访问
         *
         */
        Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
//        filterChainDefinitionMap.put("/user/add","authc");
//        filterChainDefinitionMap.put("/user/edit","authc");
        // 支持通配符配置
        filterChainDefinitionMap.put("/user/*","authc");
        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
        // 设置登录页面,没有认证或权限的会被定位到此路径
        shiroFilterFactoryBean.setLoginUrl("/toLogin");
        return shiroFilterFactoryBean;
    }

然后在templates目录下创建一个登录页面login.html,内容如下:

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>登录页面</title>
</head>
<body>
   <h3>用户登录</h3>
   <form th:action="@{/doLogin}" method="post">
       <p>用户名:<input type="text" name="username" /></p>
       <p>密码:<input type="password" name="password" /></p>
   </form>
</body>
</html>

控制器中加一个跳转的方法:
在这里插入图片描述
启动项目进行测试:
在这里插入图片描述
点击添加用户:
在这里插入图片描述
被定位到了登录页面。再点击修改用户:
在这里插入图片描述
在这里插入图片描述
同样的被定位到了登录页面。原因是在过滤器中的配置:
在这里插入图片描述
/user/下的所有路径访问都需要经过认证,因为设置成了authc,对于没有认证的,将定位到登录Url。

2.3、shiro的认证

在控制器里面加一个登录校验的方法,如下:

    /*
    * @description: 登录校验
    * @param: [username, password, model]
    * @return: java.lang.String
    * @author: yanchengzhi
    * @date: 2021/9/25 17:16
    */
    @RequestMapping("/doLogin")
    public String doLogin(@RequestParam("username") String username,
                          @RequestParam("password") String password,
                          Model model) {
        // 获取当前用户
        Subject currentUser = SecurityUtils.getSubject();
        // 如果当前用户未进行认证
        if(!currentUser.isAuthenticated()) {
            // 将用户名和密码加密封装为token
            UsernamePasswordToken token = new UsernamePasswordToken(username,password);
            try {
                // 执行登录
                currentUser.login(token);
            } catch (UnknownAccountException uae) { // 用户名不存在
                model.addAttribute("errorMsg","用户名不存在!");
                return "login";
            } catch (IncorrectCredentialsException ice) { // 密码错误
                model.addAttribute("errorMsg", "密码错误!");
                return "login";
            }
        }
        return "index";
    }

登录页面login.html修改如下:
在这里插入图片描述
登录的逻辑很简单,先获取到当前用户,如果用户没有进行认证,将前端提交过来的用户名和密码进行加密封装为一个token,然后用户带着这个token执行login方法登录。而login方法经过一系列的操作,最终会将这个token传到我们自定义UserRealm类里的doGetAuthenticationInfo方法里面:

    // 认证
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        System.out.println("进入认证方法!");
        // 用户名和密码,应该从数据库中取,这里用静态数据代替
        String name = "ycz";
        String password = "ycz123456";
        // 将token进行转换,token是前端页面传过来的用户名+密码的加密封装
        UsernamePasswordToken usernamePasswordToken = (UsernamePasswordToken) token;
        // 用户名校验
        if(!usernamePasswordToken.getUsername().equals(name)) {
            return null;  // 返回null的话,会自动抛出UnknownAccountException异常
        }
        // 密码校验,Shiro自动完成
        return new SimpleAuthenticationInfo("",password,"");
    }

然后在这个重写方法里进行用户名和密码的校验,用户名由我们自己校验,而密码则由Shiro来自动进行校验,非常安全和简单。启动项目访问进行测试。
在这里插入图片描述
先用错误的用户名进行登录:
在这里插入图片描述
控制台:
在这里插入图片描述
再用正确的用户名和错误的密码进行登录:
在这里插入图片描述
在这里插入图片描述
控制台:
在这里插入图片描述
最后用正确的用户名和正确的密码进行登录:
在这里插入图片描述
在这里插入图片描述
控制台:
在这里插入图片描述
登录成功,成功来到了首页。

2.4、整合mybatis

上面写的用户名和密码是死数据,实际上会从数据库中来查询。下面将mybatis整合进来,以便于从数据库中获取数据。

(1)pom依赖

在pom.xml中添加以下依赖坐标:

        <!--mysql驱动包-->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.11</version>
        </dependency>

        <!--德鲁伊数据源-->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.12</version>
        </dependency>

        <!-- mybatis和springboot的整合包 -->
        <dependency>
            <groupId>org.mybatis.spring.boot</groupId>
            <artifactId>mybatis-spring-boot-starter</artifactId>
            <version>2.1.3</version>
        </dependency>

        <!-- log4j依赖 -->
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>

        <!-- lombok依赖 -->
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.20</version>
            <scope>provided</scope>
        </dependency>

(2)application.yml全局配置

将前面的application.propertis内容全部放到新建的application.yml配置文件中,删除application.propertis,配置好的application.yml内容如下:

server:
  port: 8080

spring:
  application:
    name: shiro-boot
  ## 配置thymeleaf模板
  thymeleaf:
    cache: false
    check-template: true
    check-template-location: true
    servlet:
      content-type: text/html
    enabled: true
    encoding: UTF-8
    mode: HTML5
    prefix: classpath:/templates/
    suffix: .html
  ## 配置数据源
  datasource:
      url: jdbc:mysql://localhost:3306/demo?useUnicode=true&characterEncoding=utf8&useSSL=false&serverTimezone=GMT
      driver-class-name: com.mysql.cj.jdbc.Driver
      username: root
      password: ycz123456
      # 初始连接数
      initialSize: 5
      # 最小连接池数量
      minIdle: 10
      # 最大连接池数量
      maxActive: 20
      # 配置获取连接等待超时的时间
      maxWait: 60000
      # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
      timeBetweenEvictionRunsMillis: 60000
      # 配置一个连接在池中最小生存的时间,单位是毫秒
      minEvictableIdleTimeMillis: 300000
      # 配置一个连接在池中最大生存的时间,单位是毫秒
      maxEvictableIdleTimeMillis: 900000
      # 配置检测连接是否有效
      validationQuery: SELECT 1 FROM DUAL
      testWhileIdle: true
      testOnBorrow: false
      testOnReturn: false

## mybatis配置
mybatis:
  ## 实体类路径
  type-aliases-package: com.ycz.domain
  ## 映射mapper位置
  mapper-locations: classpath:mapper/*.xml

(3)建表

mysql数据库中建user表:
在这里插入图片描述
表建好后,添加几条数据:
在这里插入图片描述
(4)实体类

创建domain包,包下建立User实体类:
在这里插入图片描述

package com.ycz.shiroboot.domain;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

/**
 * @Description
 * @ClassName User
 * @Author yanchengzhi
 * @date 2021.09.25 18:48
 */
@Data
@AllArgsConstructor // 全参注解
@NoArgsConstructor // 无参注解
public class User {

    private Integer id;

    private String username;

    private String password;
}

(5)mapper层和映射文件

创建mapper包,包下创建UserMapper接口:
在这里插入图片描述

package com.ycz.shiroboot.mapper;

import com.ycz.shiroboot.domain.User;
import org.apache.ibatis.annotations.Mapper;
import org.apache.ibatis.annotations.Param;
import org.springframework.stereotype.Repository;

@Repository
@Mapper
public interface UserMapper {

    User findByUsername(@Param("username") String username);
}

在resources下创建mapper目录,下面创建UserMapper.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.ycz.shiroboot.mapper.UserMapper">

    <select id="findByUsername" parameterType="String" resultType="com.ycz.shiroboot.domain.User">
        select * from user where username = #{username}
    </select>
</mapper>

(6)service层和实现类

创建service包,包下创建接口和实现类:
在这里插入图片描述

package com.ycz.shiroboot.service;

import com.ycz.shiroboot.domain.User;

public interface UserService {

    // 通过用户名查询用户
    User findByUsername(String username);
}
package com.ycz.shiroboot.service.impl;

import com.ycz.shiroboot.domain.User;
import com.ycz.shiroboot.mapper.UserMapper;
import com.ycz.shiroboot.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

/**
 * @Description
 * @ClassName UserServiceImpl
 * @Author yanchengzhi
 * @date 2021.09.25 18:55
 */
@Service
public class UserServiceImpl implements UserService {

    @Autowired
    private UserMapper userMapper;

    @Override
    public User findByUsername(String username) {
        return userMapper.findByUsername(username);
    }
}

(7)修改UserRealm

修改自定义类UserRealm里的认证方法,现在从数据库中进行查询,而不使用死数据:

    // 认证
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
        System.out.println("进入认证方法!");
        // 将token进行转换,token是前端页面传过来的用户名+密码的加密封装
        UsernamePasswordToken usernamePasswordToken = (UsernamePasswordToken) token;
        User user = userService.findByUsername(usernamePasswordToken.getUsername());
        if(user == null) { // 用户名校验
            return null;
        }
        // 密码校验,Shiro自动完成
        return new SimpleAuthenticationInfo("",user.getPassword(),"");
    }

(8)其他修改

过滤器里添加一个登出配置,登出是shiro自带的:
在这里插入图片描述
首页加一个登出按钮:
在这里插入图片描述
这个路径/shiro/logout不是我的控制器里加的,而是shiro提供的,直接用就可以了,退出后shiro会清掉用户的缓存。

(9)测试

启动项目,到登录页面进行测试:
在这里插入图片描述
用数据库中不存在的用户名进行登录:
在这里插入图片描述
用正确的用户名和错误密码进行登录:
在这里插入图片描述
在这里插入图片描述
最后用正确的用户名和正确的密码进行登录:
在这里插入图片描述
在这里插入图片描述
OK,登录成功,来到首页,说明整合mybatis是成功的。

2.5、shiro进行授权

用户认证成功后才会进行授权,也就是用户是先进行认证后进行授权的,以下将对shiro的授权进行测试。

数据库表加一个字段用来存权限,实际上权限是单独建表存的,这里为了简单,直接加在user表里。
在这里插入图片描述
对应的User实体类也加一个属性:
在这里插入图片描述
修改认证方法的返回:
在这里插入图片描述
这个的第一个参数改为user,也就是从数据库中获取出来的,也就是即将登录的用户信息。然后修改授权方法:

    // 授权
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        System.out.println("进入授权方法!");
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        // 获取当前登录用户
        Subject subject = SecurityUtils.getSubject();
        User currentUser = (User)subject.getPrincipal();
        info.addStringPermission(currentUser.getPers());
        return info;
    }

修改过滤器里的配置:
在这里插入图片描述
这里添加了两条新的路径过滤配置,且采用了perms过滤器,即拥有权限才能访问。并且设置了没有权限的重定向url:
在这里插入图片描述
控制器里加一个方法:

    /*
    * @description: 没有权限的跳转
    * @param: []
    * @return: java.lang.String
    * @author: yanchengzhi
    * @date: 2021/9/25 20:27
    */
    @ResponseBody
    @RequestMapping("/noAuth")
    public String noAuth() {
        return "您没有权限访问该资源!";
    }

启动项目进行测试:
在这里插入图片描述
yanchengzhi这个用户是只有添加权限没有修改权限的,登录,点击添加用户:
在这里插入图片描述
在这里插入图片描述
可以访问,再点击修改用户:
在这里插入图片描述
在这里插入图片描述
退出,以另一个账号登录进去:
在这里插入图片描述
云过梦无痕这个用户没有添加权限也没有修改权限。登录成功后点击添加用户:
在这里插入图片描述
在这里插入图片描述
再点击修改用户:
在这里插入图片描述
在这里插入图片描述
测试是OK的,到这里说明权限的配置也是成功的,其他的账号就不进行测试了。

2.6、shiro整合thymeleaf

我们经常会在thymeleaf模板中根据权限信息来隐藏或显示某个按钮,这就需要在thymelaf中整合shiro,使用shiro标签进行控制。

(1)引入依赖

需要在pom中先引入thymelaf整合shiro的依赖:

        <!-- shiro和thymeleaf的整合包 -->
        <dependency>
            <groupId>com.github.theborakompanioni</groupId>
            <artifactId>thymeleaf-extras-shiro</artifactId>
            <version>2.0.0</version>
        </dependency>

需要注意版本,可能会和其他包版本有冲突,注意一下即可。

(2)配置ShiroDialect

需要在ShiroConfig中配置shiro整合thymeleaf的方言:

    /*
    * @description: shiro整合thymeleaf
    * @param: []
    * @return: at.pollux.thymeleaf.shiro.dialect.ShiroDialect
    * @author: yanchengzhi
    * @date: 2021/9/25 20:46
    */
    @Bean
    public ShiroDialect getShiroDialect(){
        return new ShiroDialect();
    }

(3)存Session

在用户登录成功后,可以往Session里存一些信息,这里的Session是Shiro提供的,而不是HttpSession。在登录方法加:
在这里插入图片描述
登录成功后,将当前用户存在了Session里。

(4)模板中使用shiro标签

在thymelaf中使用shiro标签,需要先引入命名空间:
在这里插入图片描述
然后再使用标签进行资源的显示和隐藏控制。修改后的index.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>index页面</title>
</head>
<body>
    <h1>欢迎来到首页!</h1>
    <div th:if="${session.currentUser == null}">
        <a th:href="@{/toLogin}">登录</a>
    </div>
    <h2 style="color: red;" th:text="${key}"></h2>
    <div shiro></div>
    <div shiro:hasPermission="user:add">
        <a th:href="@{/user/add}">添加用户</a> |
    </div>
    <div shiro:hasPermission="user:update">
        <a th:href="@{/user/edit}">修改用户</a> |
    </div>
    <a th:href="@{/shiro/logout}">退出</a>
</body>
</html>

(5)测试

启动项目进行测试:
在这里插入图片描述
现在没有登录,是看不到添加用户和修改用户的,点击登录,使用yanchengzhi账号登录进去:
在这里插入图片描述
在这里插入图片描述
只显示除了添加用户链接,退出,再以另一个账号登录:
在这里插入图片描述
在这里插入图片描述
只有修改用户。可以看到,这些都是使用shiro的标签来进行控制的,通过使用标签,来判断用户是否拥有某项权限,从而来限制用户的操作,这在实际开发中非常常见。

3、小结

这只是springboot整合shiro框架的一个简单入门,实际开发比这复杂的多,包括密码的加密,权限的配置拦截等,但是万变不离其宗,只要入门了,那么再复杂的都是以这为基础,学起来就会相对简单一点了。

  • 8
    点赞
  • 45
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
课程简介:历经半个多月的时间,Debug亲自撸的 “企业员工角色权限管理平台” 终于完成了。正如字面意思,本课程讲解的是一个真正意义上的、企业级的项目实战,主要介绍了企业级应用系统中后端应用权限的管理,其中主要涵盖了六大核心业务模块、十几张数据库表。 其中的核心业务模块主要包括用户模块、部门模块、岗位模块、角色模块、菜单模块和系统日志模块;与此同时,Debug还亲自撸了额外的附属模块,包括字典管理模块、商品分类模块以及考勤管理模块等等,主要是为了更好地巩固相应的技术栈以及企业应用系统业务模块的开发流程! 核心技术栈列表: 值得介绍的是,本课程在技术栈层面涵盖了前端和后端的大部分常用技术,包括Spring BootSpring MVC、Mybatis、Mybatis-Plus、Shiro(身份认证与资源授权跟会话等等)、Spring AOP、防止XSS攻击、防止SQL注入攻击、过滤器Filter、验证码Kaptcha、热部署插件Devtools、POI、Vue、LayUI、ElementUI、JQuery、HTML、Bootstrap、Freemarker、一键打包部署运行工具Wagon等等,如下图所示: 课程内容与收益: 总的来说,本课程是一门具有很强实践性质的“项目实战”课程,即“企业应用员工角色权限管理平台”,主要介绍了当前企业级应用系统中员工、部门、岗位、角色、权限、菜单以及其他实体模块的管理;其中,还重点讲解了如何基于Shiro的资源授权实现员工-角色-操作权限、员工-角色-数据权限的管理;在课程的最后,还介绍了如何实现一键打包上传部署运行项目等等。如下图所示为本权限管理平台的数据库设计图: 以下为项目整体的运行效果截图: 值得一提的是,在本课程中,Debug也向各位小伙伴介绍了如何在企业级应用系统业务模块的开发中,前端到后端再到数据库,最后再到服务器的上线部署运行等流程,如下图所示:

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值