• Springboot整合Shiro


    一、过程

    service层再建个impl包会更加层次分明
    在这里插入图片描述
    1、实验准备
    1.1 导入依赖

    <dependency>
        <groupId>org.apache.shirogroupId>
        <artifactId>shiro-springartifactId>
        <version>1.4.2version>
    dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5

    1.2 前端页面
    index.htm

    DOCTYPE html>
    <html lang="en" xmlns:th="http://www.thymeleaf.org">
    <head>
        <meta charset="UTF-8">
        <title>Titletitle>
    head>
    <body>
        <h>首页h>
        
        <div th:text="${msg}">div>
        <a th:href="@{/user/add}">adda>
        <a th:href="@{/user/update}">updatea>
    
    
    body>
    html>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    login

    DOCTYPE html>
    <html lang="en" xmlns:th="http://www.thymeleaf.org">
    <head>
        <meta charset="UTF-8">
        <title>Titletitle>
    head>
    <body>
        <h1>登录h1>
        <hr>
    
        <form th:action="@{/login}">
            用户名:<input type="text" name="username"><br>
            密码:<input type="password" name="password">
            <br>
            <input type="submit" name="提交">
        form>
    body>
    html>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    add

    DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Titletitle>
    head>
    <body>
        <h>addh>
    body>
    html>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    update

    DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Titletitle>
    head>
    <body>
        <h> update h>
    body>
    html>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    1.3 数据库准备

    create table user
    (
        id    int(20) auto_increment primary key,
        name  varchar(30) null,
        pwd   varchar(30) null,
        perms varchar(50) null
    )charset = utf8;
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    2、测试01
    设置访问权限,如果没权限则进入登陆界面

    2.1 编写Shiro配置类
    思路:ShiroFilterFactoryBean会拦截前端请求交给DefaultWebSecurityManager,再交给userRealm进行认证和授权处理
    主要编写userRealm、DefaultWebSecurityManager、ShiroFilterFactoryBean三个bean对象

    注意:我们可以从下往上写,逐步添加

    @Configuration
    public class ShiroConfig {
    
        //ShiroFilterFactoryBean (第三步:连接到前端)
        @Bean
        public ShiroFilterFactoryBean getShiroFilterBean(@Qualifier("securityManager") DefaultWebSecurityManager defaultWebSecurityManager){
            ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
            //设置安全管理器
            bean.setSecurityManager(defaultWebSecurityManager);
    
            return bean;
        }
    
        //DefaultWebSecurityManager (第二步:管理realm对象)
        @Bean(name="securityManager")
        public DefaultWebSecurityManager getDefaultWebSecurityManager(@Qualifier("userRealm") UserRealm userRealm){
            DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
            //关联UserRealm
            securityManager.setRealm(userRealm);
            return securityManager;
    
        }
    
        //创建realm对象,需要自定义类 (第一步:创建realm对象)
        @Bean(name="userRealm")  //@Bean注解后便被spring托管,不加name属性,默认name值为方法名,这里就加一下吧
        public UserRealm userRealm(){
            return new UserRealm();
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30

    在ShiroFilterFactoryBean方法内添加过滤器,设置访问权限,如果没权限则进入登陆界面

    
    ```sql
    ```sql
    //添加shiro的内置过滤器
    /*
    anon: 无需认证即可访问
    authc: 必须认证才能用
    user: 必须拥有 “记住我” 功能才能用
    perms: 拥有对某个资源的权限才能用
    role: 拥有某个角色权限才能访问
    */
    
    Map<String,String> filterMap = new LinkedHashMap<>();
    //拦截
    filterMap.put("/user/add","anon");
    filterMap.put("/user/update","authc");
    //也可使用通配符*
    //filterMap.put("/user/*","authc");
    
    bean.setFilterChainDefinitionMap(filterMap);
    //若访问时用户未认证,则跳转至登录页面
    bean.setLoginUrl("/toLogin");
    
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    2.2 编写UserRealm

    只要进行登陆操作(subject.login)就会执行doGetAuthenticationInfo方法
    //自定义UserRealm extends AuthorizingRealm
    public class UserRealm extends AuthorizingRealm {
    	//授权
        @Override
        protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
            System.out.println("执行了授权");
            return null;
        }
    
        //认证
        @Override
        protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
            System.out.println("执行了认证");
            return null;
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17

    2.3 编写HellloController进行测试结果

    @Controller
    public class HellloController {
    
        @RequestMapping({"/", "/index"})
        public String toIndex(Model model){
            model.addAttribute("msg", "hello");
            return "index";
        }
    
        @RequestMapping("/user/add")
        public String add(){
            return "/user/add";
        }
    
        @RequestMapping("/user/update")
        public String update(){
            return "/user/update";
        }
    
        @RequestMapping("/toLogin")
        public String toLogin(){
            return "login";
        }
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    3、登陆认证
    整体流程:当我们在登陆页面输入账号密码,会执行HelloController的login登陆操作,在使用subject.login(token)时会执行shiro里的UserRealm里的认证方法doGetAuthenticationInfo。

    在HelloController中添加登陆认证方法,都是根据入门案例来写的

    @RequestMapping("/login")
        public String login(String username,String password,Model model){
            //获取当前用户
            Subject subject = SecurityUtils.getSubject();
            //封装用户的登录数据
            UsernamePasswordToken token = new UsernamePasswordToken(username, password);
    
            try{
                subject.login(token); //执行登录的方法,如果没有异常就说明ok了
                return "index";
            }catch (UnknownAccountException e){ //用户名不存在
                model.addAttribute("msg","用户名不存在!");
                return "login";
            }catch (IncorrectCredentialsException e){
                model.addAttribute("msg","密码错误!");
                return "login";
            }
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    当我们执行 subject.login登陆操作时,Shiro会执行UserRealm里的认证方法doGetAuthenticationInfo

    @Override
        protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
            System.out.println("执行了认证");
    
            //用户名、密码  模拟从数据库中获取
            String name = "root";
            String password = "1111";
    
            UsernamePasswordToken userToken = (UsernamePasswordToken) token;
    
    
            if (!userToken.getUsername().equals(name)){
                return null; //抛出异常 UnknownAccountException
            }
            //密码认证,shiro做~
            return new SimpleAuthenticationInfo("",password,"");
    
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    4、整合Mybatis
    目标:使的用户登陆认证数据从数据库中取出

    4.1 导入依赖

    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>8.0.18</version>
    </dependency>
    <dependency>
        <groupId>log4j</groupId>
        <artifactId>log4j</artifactId>
        <version>1.2.17</version>
    </dependency>
    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>druid</artifactId>
        <version>1.1.21</version>
    </dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15

    4.2 配置application.yml
    这里配置mybatis扫描的包和别名

    spring:
      datasource:
        username : root
        password: qrj15521026074
        url : jdbc:mysql://localhost:3306/mybatis01?serverTimezone=UTC&useUnicode=true&characterEncoding=utf-8
        driver-class-name: com.mysql.cj.jdbc.Driver
        type: com.alibaba.druid.pool.DruidDataSource # 自定义数据源
    
        #Spring Boot 默认是不注入这些属性值的,需要自己绑定
        #druid 数据源专有配置
        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
    
        #配置监控统计拦截的filters,stat:监控统计、log4j:日志记录、wall:防御sql注入
        #如果允许时报错  java.lang.ClassNotFoundException: org.apache.log4j.Priority
        #则导入 log4j 依赖即可,Maven 地址:https://mvnrepository.com/artifact/log4j/log4j
        filters: stat,wall,log4j
        maxPoolPreparedStatementPerConnectionSize: 20
        useGlobalDataSourceStat: true
        connectionProperties: druid.stat.mergeSql=true;druid.stat.slowSqlMillis=500
    
    mybatis:
      type-aliases-package: com.qiu.pojo
      mapper-locations: classpath:mapper/*.xml
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33

    4.3配置UserMapper.xml文件

    
    DOCTYPE mapper
            PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
            "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
    
    <mapper namespace="com.qiu.mapper.UserMapper">
    
        <select id="queryUserByName" parameterType="String" resultType="com.qiu.pojo.User">
           select * from user where name = #{name};
        select>
    
    mapper>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    4.4 编写主要类和接口
    编写User类

    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    public class User {
        private Integer id;
        private String name;
        private String pwd;
        private String perms;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    编写UserMapper接口

    @Repository
    @Mapper
    public interface UserMapper {
        public User queryUserByName(String name);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    编写UserService接口

    public interface UserService {
        public User queryUserByName(String name);
    }
    
    • 1
    • 2
    • 3

    编写UserServiceImpl实现类

    @Service
    public class UserServiceImpl implements UserService{
    
        @Autowired
        UserMapper userMapper;
    
        @Override
        public User queryUserByName(String name) {
            return userMapper.queryUserByName(name);
        }
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12

    4.5 重新编写UserRealm类
    让用户数据连接数据库

     @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
            System.out.println("执行了认证");
    
          /*
            //用户名、密码  模拟从数据库中获取
            String name = "root";
            String password = "1111";
            if (!userToken.getUsername().equals(name)){
                return null; //抛出异常 UnknownAccountException
            }
            //密码认证,shiro做~
            return new SimpleAuthenticationInfo("",password,"");
            */
            
            UsernamePasswordToken userToken = (UsernamePasswordToken) token;
            //连接数据库
            User user = userService.queryUserByName(userToken.getUsername());
            if (user == null){
                return null; //抛出异常 UnknownAccountException
            }
            //密码认证,shiro做~
            return new SimpleAuthenticationInfo("",user.getPwd(),"");
    
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25

    5、请求授权
    目标:通过从数据库中获取用户权限资源,访问对应权限的方法

    5.1 重写ShiroConfig
    user类增加一个perms权限访问

    在ShiroConfig中设置拦截登陆

     @Bean
        public ShiroFilterFactoryBean getShiroFilterBean(@Qualifier("securityManager") DefaultWebSecurityManager defaultWebSecurityManager){
            ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
            //设置安全管理器
            bean.setSecurityManager(defaultWebSecurityManager);
    
            //添加shiro的内置过滤器
            /*
            anon: 无需认证即可访问
            authc: 必须认证才能用
            user: 必须拥有 “记住我” 功能才能用
            perms: 拥有对某个资源的权限才能用
            role: 拥有某个角色权限才能访问
            */
    
            Map<String,String> filterMap = new LinkedHashMap<>();
            //登陆认证拦截:未登录会跳转登陆页面
            filterMap.put("/user/add","anon");
            filterMap.put("/user/update","authc");
            //也可使用通配符*
            //filterMap.put("/user/*","authc");
    
            //登陆后授权,正常情况下没有授权会跳转到未授权页面
            filterMap.put("/user/add","perms[user:add]");
            filterMap.put("/user/update","perms[user:update]");
    
            bean.setFilterChainDefinitionMap(filterMap);
    
            //若访问时用户未认证,则跳转至登录页面
            bean.setLoginUrl("/toLogin");
    
            //若访问时用户未被授权,则跳转至未授权页面
            bean.setUnauthorizedUrl("/noauth");
    
            return bean;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36

    5.2 重写UserRealm
    添加用户的权限,从认证中获取用户信息,取出权限perms

    //授权
        @Override
        protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
            System.out.println("执行了授权");
            SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
            //授权操作
            //info.addStringPermission("user:add");
    
            //拿到当前登录的对象
            Subject subject = SecurityUtils.getSubject();
            User currentUser = (User) subject.getPrincipal(); //拿到user对象
            System.out.println(currentUser.getPerms());
            info.addStringPermission(currentUser.getPerms());
    
            return info;
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    这里要在认证doGetAuthenticationInfo方法里return时传入user资源,使之能在授权方法中使用获取权限资源

     @Override
        protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
            System.out.println("执行了认证");
    		//...................
            //这里在登陆后传入user资源
            return new SimpleAuthenticationInfo(user,user.getPwd(),"");
    
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    5.3 在HellloController添加未授权操作

    @RequestMapping("/noauth")
        @ResponseBody
        public String unauthorized(){
            return "未授权无法访问此页面";
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    6、整合thymeleaf
    目标:实现特点用户访问特定页面,权限不同,访问到的功能不同
    6.1 导入依赖

     
     <dependency>
         <groupId>org.thymeleafgroupId>
         <artifactId>thymeleaf-spring5artifactId>
         <version>3.0.11.RELEASEversion>
     dependency>
     <dependency>
         <groupId>org.thymeleaf.extrasgroupId>
         <artifactId>thymeleaf-extras-java8timeartifactId>
         <version>3.0.4.RELEASEversion>
     dependency>
    
    
    <dependency>
        <groupId>com.github.theborakompanionigroupId>
        <artifactId>thymeleaf-extras-shiroartifactId>
        <version>2.0.0version>
    dependency>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18

    6.2 在ShiroConfig添加整合thymeleaf

     //整合ShiroDialect:用来整合shiro thymeleaf
        @Bean
        public ShiroDialect getShiroDialect(){
            return new ShiroDialect();
        }
    
    • 1
    • 2
    • 3
    • 4
    • 5

    6.3 使用thymeleaf重写index登陆页面
    导入shiro和thymeleaf的约束

    通过shiro:hasPermission指定权限

    DOCTYPE html>
    <html lang="en" xmlns:th="http://www.thymeleaf.org"
          xmlns:shiro="http://www.thymeleaf.org/thymeleaf-extras-shiro" >
    <head>
        <meta charset="UTF-8">
        <title>Titletitle>
    head>
    <body>
    <h1>首页h1>
        <div th:if="${session.loginUser==null}">
            <a th:href="@{/toLogin}">登录a>
        div>
        <p th:text="${msg}">p>
        <hr>
        <div shiro:hasPermission="user:add">
            <a th:href="@{/user/add}">adda>
    	div>
        <div shiro:hasPermission="user:update">
            <a th:href="@{/user/update}">updatea>
        div>
    
        <a th:href="@{/logout}">注销a>
    body>
    html>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24

    7、结果
    数据库权限
    在这里插入图片描述
    root账号登陆界面
    在这里插入图片描述
    在这里插入图片描述
    二、实验问题
    1、插件报错
    打包遇到错误Failed to execute goal org.apache.maven.plugins:maven-surefire-plugin:2.22.2:test

    解决办法:修改pom.xml文件

    <plugins>
    	<plugin>
    		<groupId>org.apache.maven.pluginsgroupId>
    		<artifactId>maven-surefire-pluginartifactId>
    		<version>2.19.1version>
    	plugin>
    plugins>
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    2、IDEA2020.1启动SpringBoot项目出现java程序包:xxx不存在

    setting->bulid,execution,Deployment->bulid tools->maven->runner

    勾选上Delegate ide bulid/run actions to Maven

  • 相关阅读:
    【python零基础入门学习】python基础篇(基础结束篇)之数据结构类型-列表,元组,字典,集合(五)
    asp.net 在线音乐网站系统VS开发sqlserver数据库web结构c#编程Microsoft Visual Studio
    Python操控HDFS
    git rebase
    数学建模的论文手应该如何准备?
    k8s使用时无法ping通服务器From IP地址 icmp_seq=1 Destination Host Unreachable
    linux检测系统是否被入侵(上)
    简单介绍 Vue 3.0 项目创建
    Servlet导坐标,创建入门(有图有代码有过程)
    2023.9.11 关于传输层协议 UDP和TCP 详解
  • 原文地址:https://blog.csdn.net/qq_41512902/article/details/125968391