IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> Java知识库 -> Springboot之Shiro -> 正文阅读

[Java知识库]Springboot之Shiro

一、导入依赖

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

二、编写config

由于Shiro没有被SpringBoot所集成 所以我们要手动配置javaconfig

在这里插入图片描述

一共分为两个 shiroconfig用来进行核心文件的配置 userRealm用来进行用户的授权和登录验证

  • ShiroConfig
package com.llf.Config;

@Configuration
public class ShiroConfig {
    @Autowired
     private UserRealm userRealm;
    @Autowired
    private  DefaultWebSecurityManager SecurityManager;

    // ShiroFilterFactoryBean
    @Bean
    public ShiroFilterFactoryBean getshiroFilterFactoryBean(){
        ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
      //设置安全管理器
        bean.setSecurityManager(SecurityManager);
        return  bean;
    }
    //DefaultWebSecurityManager
    @Bean
    public DefaultWebSecurityManager  getdefaultWebSecurityManager(){
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
  
        return securityManager;
    }

    //创建UesrRealm对象 需要自定义类
    @Bean
    public UserRealm userRealm(){
        return  new UserRealm();
    }

}

  • UserRealm

    package com.llf.Config;
    //自定义授权和认证
    public class UserRealm extends AuthorizingRealm {
        //授权
        @Override
        protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
    
            return null;
        }
        //认证
        @Override
        protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
    
            return null;
        }
    }
    
    

    这样子一个shiro的基本结构就算搭好了

三、用户拦截功能的实现

环境准备

  • 首先将需要的页面准备好 首页 add页面 update页面
<!--index-->
<!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>首页</title>
</head>
<body>
<h1 >首页</h1>
<div th:text="${msg}"></div>
<h1><a th:href="@{/tohello}">hello</a></h1>
<h1><a th:href="@{/toadd}">add</a></h1>
<h1><a th:href="@{/toupdate}">update</a></h1>
</body>
</html>

<!--add-->

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h1>add</h1>
</body>
</html>

<!--update-->
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h1>update</h1>
</body>
</html>


<!--hello-->
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h1 style="text-align:center">欢迎光临</h1>
</body>
</html>
  • Controller控制视图跳转
@org.springframework.stereotype.Controller
public class Controller {

    @RequestMapping("/")
    public String toindex(Model model){
        model.addAttribute("msg","hello shhiro");
        return "index";
    }
    @RequestMapping("/toadd")
    public String toadd(){
        return "user/add";
    }
    @RequestMapping("/toupdate")
    public String toupdate(){
        return "user/update";
    }
    @RequestMapping("/tohello")
    public String tohello(){
        return "user/hello";
    }
}

访问权限设置

现在我们约定,只有登录的人才能访问所有页面

于是我们需要在shiroconfig中进行配置

    //设置过滤器
        /*
            anon:无需认证直接访问
            authc:必须认证才能访问
            user:必须拥有记住我功能才能访问
            perms:拥有对某个资源的权限才能访问
         */
        Map<String, String> FilterMap = new LinkedHashMap<>();
        //拦截条件设置
        FilterMap.put("/user/**","authc");

只有认证的人才能访问user包下的所有文件

package com.llf.Config;

@Configuration
public class ShiroConfig {
    @Autowired
     private UserRealm userRealm;
    @Autowired
    private  DefaultWebSecurityManager SecurityManager;


    // ShiroFilterFactoryBean
    @Bean
    public ShiroFilterFactoryBean getshiroFilterFactoryBean(){
        ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
        //设置安全管理器
        bean.setSecurityManager(SecurityManager);
     /*===================================================================*/
        //设置过滤器
        /*
            anon:无需认证直接访问
            authc:必须认证才能访问
            user:必须拥有记住我功能才能访问
            perms:拥有对某个资源的权限才能访问
         */
        Map<String, String> FilterMap = new LinkedHashMap<>();
        //拦截条件设置
        FilterMap.put("/user/hello","authc");
        bean.setFilterChainDefinitionMap(FilterMap);
   /*===================================================================*/
        return  bean;
    }

    //DefaultWebSecurityManager
    @Bean
    public DefaultWebSecurityManager  getdefaultWebSecurityManager(){
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        //关联realm

        securityManager.setRealm(userRealm);
        return securityManager;
    }

    //创建UesrRealm对象 需要自定义类
    @Bean
    public UserRealm userRealm(){
        return  new UserRealm();
    }

}

在这里插入图片描述

四、 登录页面跳转

访问权限受阻,我们应该让它自动跳到登录页面进项登录验证,于是我们被迫写一个login页面和login请求

<!DOCTYPE html>
<html lang="en" xmlns:th="http://www.thymeleaf.org">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<h1>
    <div th:text="${gg}"style="color: red"></div>
<form th:action="@{/login}" method="post">
    用户名:<input type="text" name="username" onautocomplete="false"><br/>&nbsp;&nbsp;码:<input type="password" name="password"><br/>
    <input type="submit" value="提交">
</form>
</h1>
</body>
</html>
@RequestMapping("/tologin")
public String tologin(){
    return "user/login";
}

然后在配置类中配置登录页面

  //跳转登录网站
        bean.setLoginUrl("/tologin");
package com.llf.Config;

@Configuration
public class ShiroConfig {
    @Autowired
     private UserRealm userRealm;
    @Autowired
    private  DefaultWebSecurityManager SecurityManager;


    // ShiroFilterFactoryBean
    @Bean
    public ShiroFilterFactoryBean getshiroFilterFactoryBean(){
        ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
        //设置安全管理器
        bean.setSecurityManager(SecurityManager);
        //设置过滤器
        /*
            anon:无需认证直接访问
            authc:必须认证才能访问
            user:必须拥有记住我功能才能访问
            perms:拥有对某个资源的权限才能访问
         */
        Map<String, String> FilterMap = new LinkedHashMap<>();
        //拦截条件设置
        FilterMap.put("/user/hello","authc");
        bean.setFilterChainDefinitionMap(FilterMap);
    /*===================================================================*/
        //跳转登录网站
        bean.setLoginUrl("/tologin");
   /*===================================================================*/
        return  bean;
    }

    //DefaultWebSecurityManager
    @Bean
    public DefaultWebSecurityManager  getdefaultWebSecurityManager(){
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        //关联realm

        securityManager.setRealm(userRealm);
        return securityManager;
    }

    //创建UesrRealm对象 需要自定义类
    @Bean
    public UserRealm userRealm(){
        return  new UserRealm();
    }

整合mybatis

登录就涉及到账号密码等问题,所以我们还得链接数据库 整合mybatis

  • 导入依赖、配置数据源

       <!-- mysql驱动 -->        
    	<dependency>
                <groupId>mysql</groupId>
                <artifactId>mysql-connector-java</artifactId>
            </dependency>
       <!--  德鲁伊数据源  可用可不用-->       
            <dependency>
                <groupId>com.alibaba</groupId>
                <artifactId>druid</artifactId>
                <version>1.2.6</version>
            </dependency>
       <!-- log4j  配合德鲁伊数据源 -->       
            <dependency>
                <groupId>log4j</groupId>
                <artifactId>log4j</artifactId>
                <version>1.2.17</version>
            </dependency>
       <!-- mybatis整合springboot -->       
            <dependency>
                <groupId>org.mybatis.spring.boot</groupId>
                <artifactId>mybatis-spring-boot-starter</artifactId>
                <version>2.2.0</version>
            </dependency>然后就是数据源配置 
    
    spring:
      datasource:
        driver-class-name: com.mysql.cj.jdbc.Driver
        url: jdbc:mysql://localhost:3306/mydb1?serverTimezone=UTC
        username: root
        password: 123456
        type: com.alibaba.druid.pool.DruidDataSource
        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.llf.Pojo
      mapper-locations: classpath:Mapper/*.xml
    
    
  • 编写Pojo Mapper、Service

    。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。。
    

数据验证

  • 在Controller中进行逻辑判断
    @RequestMapping("/login")
    public  String login(String username, String password, Model model, HttpSession session){
        //获取当前用户
        Subject subject = SecurityUtils.getSubject();
        //封装用户数据到令牌  token 令牌
        UsernamePasswordToken token = new UsernamePasswordToken(username,password);
        //执行登录操作
        try{
            subject.login(token);
            session.setAttribute("username",username);
            return "index";
        }catch ( UnknownAccountException e){
            //用户名不存在
            model.addAttribute("gg","用户名不存在");
            return "user/login";
        }catch (IncorrectCredentialsException e){
            //密码错误
            model.addAttribute("gg","密码错误");
            return "user/login";
        }
抛出的异常 我们只需要将其名字写出 并指定如何跳转  shrio会自动对其进行判断错误类型
  • 在UserRealm对前端的数据和数据库中的数据进行匹配

          @Autowired
        private ShiroServiceImpl shiroService;
    	Shiro user = shiroService.quaryByName(usertoken.getUsername());
            if (user == null){
                //说明这个用户不存在
                return null;
            }
    返回null shiro会自动根据我们抛出的异常判断错误类型
    

在这里插入图片描述

在这里插入图片描述

五、注销

登录成功之后就应该有注销功能, 这个功能Shiro也帮我们做好了 我们只需要将页面和请求写好即可

  • 于是我们在主页中完善注销选项
<a th:href="@{/logout}" ><button class="btn btn-sm btn-success" >注销</button></a>

编写controller请求

    @RequestMapping("/logout")
    public String logout(){
        return "index";

在配置类中配置注销

//注销
  FilterMap.put("/logout","logout");
package com.llf.Config;

@Configuration
public class ShiroConfig {
    @Autowired
     private UserRealm userRealm;
    @Autowired
    private  DefaultWebSecurityManager SecurityManager;


    // ShiroFilterFactoryBean
    @Bean
    public ShiroFilterFactoryBean getshiroFilterFactoryBean(){
        ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
        //设置安全管理器
        bean.setSecurityManager(SecurityManager);
        //设置过滤器
        /*
            anon:无需认证直接访问
            authc:必须认证才能访问
            user:必须拥有记住我功能才能访问
            perms:拥有对某个资源的权限才能访问
         */
        Map<String, String> FilterMap = new LinkedHashMap<>();
        //拦截条件设置
        FilterMap.put("/user/hello","authc");
 /*===================================================================*/
        //注销
 		 FilterMap.put("/logout","logout");
 /*===================================================================*/
        bean.setFilterChainDefinitionMap(FilterMap);
     	//跳转登录网站
        bean.setLoginUrl("/tologin");
        

        return  bean;
    }

    //DefaultWebSecurityManager
    @Bean
    public DefaultWebSecurityManager  getdefaultWebSecurityManager(){
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        //关联realm

        securityManager.setRealm(userRealm);
        return securityManager;
    }

    //创建UesrRealm对象 需要自定义类
    @Bean
    public UserRealm userRealm(){
        return  new UserRealm();
    }

六、个性化定制

按照常理 我们应该在没有登录的时候显示登录按钮 登录之后显示注销按钮 那么我们应该怎么做?

导入thymeleaf–shiro整合包

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

将ShiroDialec注入Bean

@Bean
    public ShiroDialect getShiroDialect(){
        return  new ShiroDialect();
    }

在登录验证成功的时候注入session

在controller的登录判断中 登陆成功 创建一个session

            session.setAttribute("username",username);
    @RequestMapping("/login")
    public  String login(String username, String password, Model model, HttpSession session){
        //获取当前用户
        Subject subject = SecurityUtils.getSubject();
        //封装用户数据到令牌  token 令牌
        UsernamePasswordToken token = new UsernamePasswordToken(username,password);
        //执行登录操作
        try{
            subject.login(token);
    /*===================================================================*/
            session.setAttribute("username",username);
   /*===================================================================*/
            return "index";
        }catch ( UnknownAccountException e){
            //用户名不存在
            model.addAttribute("gg","用户名不存在");
            return "user/login";
        }catch (IncorrectCredentialsException e){
            //密码错误
            model.addAttribute("gg","密码错误");
            return "user/login";
        }


    }

在index.html页面引入thymeleaf命名空间

xmlns:th="http://www.thymeleaf.org"

在登录、注销的div中进行th:if判断 看session是否为空 如果为空就显示登录按钮 如果不为空 就显示注销按钮

<div th:if="${session.username}==null" >
    <a th:href="@{/tologin}" ><button class="btn btn-sm btn-success" >登录</button></a>
</div>
<div th:if="${session.username}" >
<a th:href="@{/logout}" ><button class="btn btn-sm btn-success" >注销</button></a>
</div>

在这里插入图片描述

七、不同权限的人显示不同页面

在页面初始化阶段 ,我们写了几个页面 但是在截图中 却没有看到add、update页面 这是怎么做到的呢?

首先导入thymeleaf–shiro整合包

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

将ShiroDialec注入Bean

@Bean
    public ShiroDialect getShiroDialect(){
        return  new ShiroDialect();
    }

在UserRealm类中进行权限授予

 //拿到当前登录的对象
  Subject subject = SecurityUtils.getSubject();
 Shiro currentUser = (Shiro) subject.getPrincipal();
//设置用户权限
info.addStringPermission(currentUser.getRole());

在这里插入图片描述

在config类中进行权限访问设置

       /*
            anon:无需认证直接访问
            authc:必须认证才能访问
            user:必须拥有记住我功能才能访问
            perms:拥有对某个资源的权限才能访问
         */
//用户 拥有shiro:add权限 才能访问
FilterMap.put("/toadd","perms[shiro:add]");
//用户 拥有shiro:update权限 才能访问
FilterMap.put("//toupdate","perms[shiro:update]");

在index里进行显示设置

  • 首先导入thymeleaf与shiro整合的命名空间
 xmlns:shiro="http://www.thymeleaf.org/thymeleaf-extras-shiro"

观察它与thymeleaf和Security整合的命名空间有什么区别?

区别就是 它是由Thymeleaf命名空间+/+各自整合包的名字

  • 在add、update页面的div中进行判断

    <!--判断用户的权限  有这个权限就显示这个功能-->
    <div shiro:hasPermission="shiro:add">
    	<h1>
            <a th:href="@{/toadd}">add
            </a>
        </h1>
    </div>
    <div shiro:hasPermission="shiro:update">
    	<h1>
            <a th:href="@{/toupdate}">update
            </a>
        </h1>
    </div>
    

    由于用户在登录的时候 我们从数据库中将其拥有的权限赋予了他 所以在这我们就可以进行判断

在这里插入图片描述

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-20YLYM62-1626956143028)(C:\Users\machenike\AppData\Roaming\Typora\typora-user-images\image-20210722200703440.png)]

根据不同的权限 我们就让其显示了不同的页面

注意

这里有一个坑 我们页面的访问请求和权限设置的请求一定要和Controller中的mapping请求一致 要不然就会出现任何人都能访问任何页面的bug

在这里插入图片描述

配置类总代码

package com.llf.Config;

import at.pollux.thymeleaf.shiro.dialect.ShiroDialect;
import org.apache.shiro.spring.web.ShiroFilterFactoryBean;
import org.apache.shiro.web.mgt.DefaultWebSecurityManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

import java.util.LinkedHashMap;
import java.util.Map;

@Configuration
public class ShiroConfig {
    @Autowired
     private UserRealm userRealm;
    @Autowired
    private  DefaultWebSecurityManager SecurityManager;


    // ShiroFilterFactoryBean
    @Bean
    public ShiroFilterFactoryBean getshiroFilterFactoryBean(){
        ShiroFilterFactoryBean bean = new ShiroFilterFactoryBean();
        //设置安全管理器
        bean.setSecurityManager(SecurityManager);
        //设置过滤器
        /*
            anon:无需认证直接访问
            authc:必须认证才能访问
            user:必须拥有记住我功能才能访问
            perms:拥有对某个资源的权限才能访问
         */
        Map<String, String> FilterMap = new LinkedHashMap<>();
        //拦截条件设置
        FilterMap.put("/user/hello","user");
        //用户 拥有shiro:add权限 才能访问
        FilterMap.put("/toadd","perms[shiro:add]");
        FilterMap.put("//toupdate","perms[shiro:update]");
        //注销
        FilterMap.put("/logout","logout");
        bean.setFilterChainDefinitionMap(FilterMap);
        //未授权页面
        bean.setUnauthorizedUrl("/unauthorized");
        //跳转登录网站
        bean.setLoginUrl("/tologin");

        return  bean;
    }

    //DefaultWebSecurityManager
    @Bean
    public DefaultWebSecurityManager  getdefaultWebSecurityManager(){
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        //关联realm

        securityManager.setRealm(userRealm);
        return securityManager;
    }

    //创建UesrRealm对象 需要自定义类
    @Bean
    public UserRealm userRealm(){
        return  new UserRealm();
    }

    //整合ShiroDialect

    @Bean
    public ShiroDialect getShiroDialect(){
        return  new ShiroDialect();
    }
}
 
 UserRealm
 package com.llf.Config;

import com.llf.Pojo.Shiro;
import com.llf.Service.ShiroServiceImpl;
import org.apache.catalina.User;
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.session.Session;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.subject.Subject;
import org.springframework.beans.factory.annotation.Autowired;

//自定义授权和认证
public class UserRealm extends AuthorizingRealm {

    @Autowired
    private ShiroServiceImpl shiroService;
    //授权
    @Override

    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        SimpleAuthorizationInfo info= new SimpleAuthorizationInfo();
       //拿到当前登录的对象
        Subject subject = SecurityUtils.getSubject();
        Shiro currentUser = (Shiro) subject.getPrincipal();
        //设置用户权限
        info.addStringPermission(currentUser.getRole());
        return info;
    }


    //认证
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {

        //从数据库中查询验证
        UsernamePasswordToken usertoken = (UsernamePasswordToken) token;
        Shiro user = shiroService.quaryByName(usertoken.getUsername());
        if (user == null){
            //说明这个用户不存在
            return null;
        }


        //密码认证
        //principal 将user放在第一个参数 可以将当前登录的对象传递到上面被访问
        return new SimpleAuthenticationInfo(user,user.getPassword(),"");
    }
}

  Java知识库 最新文章
计算距离春节还有多长时间
系统开发系列 之WebService(spring框架+ma
springBoot+Cache(自定义有效时间配置)
SpringBoot整合mybatis实现增删改查、分页查
spring教程
SpringBoot+Vue实现美食交流网站的设计与实
虚拟机内存结构以及虚拟机中销毁和新建对象
SpringMVC---原理
小李同学: Java如何按多个字段分组
打印票据--java
上一篇文章      下一篇文章      查看所有文章
加:2021-07-23 10:35:34  更:2021-07-23 10:37:31 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年12日历 -2024/12/18 18:13:12-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码