Shiro-SpringBoot (一)

news2024/9/25 11:10:17

前不久负责项目中刚好也使用了Shiro做权限控制,趁着空闲期想把之前做的整理一下。在日常项目开发中,权限认证是不可少的模块。比较常用的有Spring Security,或是轻量级的Apache Shiro。相对来说Shiro提供了认证、授权、加密、会话管理、与Web集成、缓存等。这些都是日常会用到的,而且Shiro的API比较简洁,学习成本相对低。接下来将整理一下在SpringBoot中如何集成Shiro:

  • RBAC介绍
  • SpringBoot集成Shiro和配置
  • Shiro的登录和认证
  • 当前不足点

(一) RBAC介绍

**RBAC(Role-Based Access Control )**基于角色访问控制,在权限设计上用户是基于角色进行权限认证,而角色又是和资源相关联的。这样在设计和管理上简化了权限的操作,它们都是层级依赖,更方便我们的管理。如此一来,数据库表设计可以如下图:
cmd-markdown-logo

(二) SpringBoot集成Shiro和配置

1、导入Shiro依赖

pom.xml中加入以下依赖

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

2、配置Shiro

在配置之前,首先了解一下Shiro中主要功能,并看看它们主要是做什么的。

  • Subject 安全视角下与软件交互的实体(用户,第三方服务等等)
  • Authenticator 用户登录时进行账户的认证
  • Authorizer 用户登录时进行账户的权限资源认证
  • Realms每当执行认证或授权时,shiro会从程序配置的一个或多个Realm中查询

新建JAVAShiroRealm用于继承ShiroAuthorizingRealm抽象类,并复写doGetAuthenticationInfodoGetAuthorizationInfo用于账户和权限的认证。

public class ShiroRealm extends AuthorizingRealm {

    @Autowired
    private UserService userService;

    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        UsernamePasswordToken token = (UsernamePasswordToken) authenticationToken;
        String userName = token.getUsername();
        String password = new String((char[])token.getCredentials());
        //这里可以自行查询数据库进行验证
        if(userName != "zhangshan" && password != DigestUtils.md5Hex("123456")) {
            throw new UnknownAccountException ("未知的账户认证失败");
        }
        SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(
                userName, //用户名
                DigestUtils.md5Hex("123456"), //密码
                getName()  //realm name
        );
        //存入session
        //SecurityUtils.getSubject().getSession().setAttribute("user", user);
        return authenticationInfo;
    }

    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        String useCode = (String) principalCollection.getPrimaryPrincipal();
        SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();
        Map<String,Object> userAuthorityInfoMap = userService.getUserAuthorityInfo(useCode);
        //这里可以从数据库进行查询
        List<String> roles = new ArrayList<String>();
        List<String> perms = mew ArrayList<String>();
        roles.add("管理员");
        perms.add("查看用户模块");
        simpleAuthorizationInfo.addRoles(roles);
        simpleAuthorizationInfo.addStringPermissions(perms);
        return simpleAuthorizationInfo;
    }

}

SpringBoot中配置Shiro,配置URL过滤规则

@Configuration
public class ShiroConfiguration {

    /**
     * 负责org.apache.shiro.util.Initializable类型bean的生命周期的,初始化和销毁。
     */
    @Bean(name = "lifecycleBeanPostProcessor")
    public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
        return new LifecycleBeanPostProcessor();
    }

    /**
     * shiro密码认证配置,使用MD5 HEX16进制
     */
    @Bean(name = "hashedCredentialsMatcher")
    public HashedCredentialsMatcher hashedCredentialsMatcher() {
        HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher();
        credentialsMatcher.setHashAlgorithmName("MD5");
        credentialsMatcher.setHashIterations(1);//散列的次数,相当于md5("");
        credentialsMatcher.setStoredCredentialsHexEncoded(true);//采用HEX16进制编码
        return credentialsMatcher;
    }

    /**
     * ShiroRealm,需要自己实现自定义的认证类,继承自AuthorizingRealm,负责用户的认证和权限的处理
     */
    @Bean(name = "shiroRealm")
    @DependsOn("lifecycleBeanPostProcessor")
    public ShiroRealm shiroRealm() {
        ShiroRealm realm = new ShiroRealm();
        //realm.setCacheManager(ehCacheManager());
        return realm;
    }

    /**
     * EhCacheManager,缓存管理,用户登陆成功后,把用户信息和权限信息缓存起来,
     * 然后每次用户请求时,放入用户的session中,如果不设置这个bean,每个请求都会查询一次数据库。
     */
//    @Bean(name = "ehCacheManager")
//    @DependsOn("lifecycleBeanPostProcessor")
//    public EhCacheManager ehCacheManager() {
//        EhCacheManager ehcacheManager = new EhCacheManager();
//        //ehcacheManager.setCacheManagerConfigFile("classpath:config/ehcache-shiro.xml");
//        return ehcacheManager;
//    }

    /**
     * SecurityManager权限管理,主营管理登陆,登出,权限,session的处理
     */
    @Bean(name = "securityManager")
    public DefaultWebSecurityManager securityManager() {
        DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
        securityManager.setRealm(shiroRealm());
        //securityManager.setCacheManager(ehCacheManager());
        return securityManager;
    }

    /**
     * ShiroFilterFactoryBean配置URL过滤链规则
     */
    @Bean(name = "shiroFilter")
    public ShiroFilterFactoryBean shiroFilterFactoryBean() {
        ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
        shiroFilterFactoryBean.setSecurityManager(securityManager);
        shiroFilterFactoryBean.setLoginUrl("/login");
        shiroFilterFactoryBean.setSuccessUrl("/index");
        shiroFilterFactoryBean.setUnauthorizedUrl("/pages/403");
        Map<String, String> filterChainDefinitionMap = new LinkedHashMap<String, String>();
        //Shiro拦截URL规则
        filterChainDefinitionMap.put("/logout", "logout");
        filterChainDefinitionMap.put("/js/**", "anon");
        filterChainDefinitionMap.put("/css/**", "anon");
        filterChainDefinitionMap.put("/login", "anon");
        filterChainDefinitionMap.put("/403", "anon");
        filterChainDefinitionMap.put("/userInfo/**", "authc,perms[查看用户模块]");
        filterChainDefinitionMap.put("/messageInfo/**", "authc,roles[管理员]");
        filterChainDefinitionMap.put("/**", "authc");
        shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
        return shiroFilterFactoryBean;
    }

    /**
     * 由Advisor决定对哪些类的方法进行AOP代理。
     */
    @Bean
    @ConditionalOnMissingBean
    public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
        DefaultAdvisorAutoProxyCreator defaultAAP = new DefaultAdvisorAutoProxyCreator();
        defaultAAP.setProxyTargetClass(true);
        return defaultAAP;
    }

    /**
     * shiro里实现的Advisor类,内部使用AopAllianceAnnotationsAuthorizingMethodInterceptor来拦截用以下注解的方法。
     */
    @Bean
    public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor() {
        AuthorizationAttributeSourceAdvisor aASA = new AuthorizationAttributeSourceAdvisor();
        aASA.setSecurityManager(securityManager());
        return aASA;
    }

}

(三) Shiro的登录和认证

新建LoginController进行登录验证Shiro。在subject.login(token)这行代码执行的时候,Shiro会回调我们上面实现的ShiroRealm进行账户认证和权限认证。

@RequestMapping("/login")
@Controller
public class LoginController {

    private static Logger logger = LoggerFactory.getLogger(LoginController.class);

    @RequestMapping(method = RequestMethod.GET)
    @ResponseBody
    public String loginPage(){
        return "login";
    }

    @RequestMapping(value = "/check",method = RequestMethod.POST)
    @ResponseBody
    public String login(@RequestParam("userName") String userName, @RequestParam("passWord") String passWord){
        Subject subject = SecurityUtils.getSubject();
        UsernamePasswordToken token = new UsernamePasswordToken(userCode, DigestUtils.md5Hex(passWord));
        try {
            subject.login(token);
        } catch (Exception e) {
            logger.error("用户用户名和密码..验证未通过");
            return "redirect:/login";
        }
        // catch (UnknownAccountException e) {
            // logger.error("未知的账户认证失败);
        // } catch (DisabledAccountException e) {
            // logger.error("账户已经被禁用,认证失败");
        // }

         return "/index";
    }

}

(四) 当前不足点

到这里Shiro已经可以进行登录验证,在配置中也可以对指定的URL拦截,并通过角色和资源认证才可以访问。但是细心想想,还是有一些不足,在一下节将对其进行优化,主要有以下几点

  • 不支持AJAX的调用,目前只能重定向页面,这对于一些前后端分离的开发是不满足的
  • 不支持前台FreeMarker模板页面元素的权限控制,包括按钮、文字等
  • URL拦截冗余在代码,虽然说SpringBoot提倡JAVA Configuration配置,但我们还是想要单独写到配置文件,例如yml或是properties

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/56636.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

华为机试 - 羊、狼、农夫过河

目录 题目描述 输入描述 输出描述 用例 题目解析 算法源码 题目描述 羊、狼、农夫都在岸边&#xff0c;当羊的数量小于狼的数量时&#xff0c;狼会攻击羊&#xff0c;农夫则会损失羊。农夫有一艘容量固定的船&#xff0c;能够承载固定数量的动物。 要求求出不损失羊情况…

体验Vue3的SSR框架 - Nuxt3

SSR 与 Nuxt SSR 是 Server-Side Rendering&#xff0c;即服务端渲染的英文缩写。 Vue.js 是一个用于构建客户端应用的框架。默认情况下&#xff0c;Vue 组件的职责是在浏览器中生成和操作 DOM。在客户端是单页应用 (SPA) 。 也可以将 vue 程序在服务端渲染&#xff0c;渲染…

【GD-1开发板】CH340驱动安装方法

CH340驱动安装方法正常情况异常情况CH340驱动安装步骤现在国产ARM替代STM32的arm芯片运动正如火如荼进行中&#xff0c;我也录制了一套完整的”ARM嵌入式开发入门教程“&#xff0c;并配套了一个GD32F103C8T6的开发板。 但有小伙伴拿到板子后&#xff0c;说下载程序的时候&…

实验七:定时/计数器8253、8254

目录 例实验目的实验内容报告要求例 已知8253的两个计数器CLK0=1MHZ,CLK1=1KHZ,现系统要求8253的OUT1产生0.1s的定时方波信号。 (1):应如何实现? (2):说明两个计数器的工作方式并计算计数初值 (3):编写初始化程序(8253的端口地址80H-83H,均采用二进制计数) C…

详解torch.nn.functional.grid_sample函数(通俗易懂):可实现对特征图的水平/垂直翻转

一、函数介绍 Pytorch中grid_sample函数的接口声明如下&#xff0c;具体网址可以点这里 torch.nn.functional.grid_sample(input, grid, mode‘bilinear’, padding_mode‘zeros’, align_cornersNone) 为了简单起见&#xff0c;以下讨论都是基于如下参数进行实验及讲解的&…

BSN开放联盟链“中移链”浏览器2.0正式发布!

由中国移动信息技术中心自主研发的中移链EOS区块链浏览器2.0版本&#xff0c;已在区块链服务网络&#xff08;BSN&#xff09;官网和BSN-DDC网络官网正式发布。 中移链浏览器2.0 无论是从政策导向还是从业务需求方面来说&#xff0c;区块链技术的发展已经是一种不可逆的趋势&a…

查找-二叉排序树

问题引入 【问题描述】 输入若干个整数建立二叉排序树,以0结束输入,在二叉排序树上查找关键字,删除指定关键字结点。 【输入形式】 (1)第一行,输入若干个整数,输入0结束输入; 如输入关键字 45 24 53 12 28 90 0 可建立如下二叉排序树 (2)第二行,输入两个整数,一…

GameOff2022参与有感

GameOff2022参与有感以及年度总结 厚颜无耻的用我们美术的立绘 GameOff— Redemption 很高兴在一个月的时间里面和大家一起完成了《Redemption》 比赛链接&#xff1a;Itch.io 百度云盘链接&#xff1a; 链接&#xff1a;https://pan.baidu.com/s/1ylK0QRr2lmkqi4JF1wsXtA 提…

【servelt原理_6_servlet核心接口和类】

servlet核心接口和类 在Servlet体系中&#xff0c;除了实现servlet接口,还可以通过继承GenericServlet或HttpServlet类实现编写1.Servlet接口 servlet接口是整个servlet的核心。它是所有Servlet类必须直接或者间接实现的一个接口&#xff0c;其内部需要实现的5个方法分别关乎…

基于flv.js的视频自动播放

1: html <video class"video-content" id"video">您的浏览器不支持 HTML5 video&#xff01; </video> 2: 创建flv实例并播放 let videoPlayer document.getElementById(video); //获取html if (flvJs.isSupported()) {//创建flv实例this.P…

音视频开发——FFmpeg技术点 【进阶一览】

概述 Fmpeg是一套领先的音视频多媒体处理开源框架&#xff0c;采用LGPL或GPL许可证。它提供了对音视频的采集、编码、解码、转码、音视频分离、合并、流化、过滤器等丰富的功能&#xff0c;包含了非常先进的音频/视频编解码库libavcodec&#xff0c;具有非常高的可移植性和编解…

[附源码]计算机毕业设计中小学课后延时服务管理系统Springboot程序

项目运行 环境配置&#xff1a; Jdk1.8 Tomcat7.0 Mysql HBuilderX&#xff08;Webstorm也行&#xff09; Eclispe&#xff08;IntelliJ IDEA,Eclispe,MyEclispe,Sts都支持&#xff09;。 项目技术&#xff1a; SSM mybatis Maven Vue 等等组成&#xff0c;B/S模式 M…

Git 之 已有项目创建 git 仓库

Git 之 已有项目创建 git 仓库前言一、现在 github/gitee 中创建仓库二、在项目的文件夹当中 git bash here1.git init2. git remote add origin 仓库地址3. git pull origin master4. git add . git commit -m git push -u origin master前言 项目已经开始写了,但是还没有…

干货 | 数字经济创新创业——如何造就成功的职业生涯

下文整理自清华大学大数据能力提升项目能力提升模块课程“Innovation & Entrepreneurship for Digital Economy”&#xff08;数字经济创新创业课程)的精彩内容。主讲嘉宾&#xff1a;Kris Singh: CEO at SRII, Palo Alto, CaliforniaVisiting Professor of Tsinghua Unive…

第一天:Python元学习——通用人工智能的实现

文章目录0 封面1 第一章&#xff1a;元学习简介1.1 元学习与少样本学习1.2 元学习的类型——学习度量空间1.3 学习初始化1.4 学习优化器1.5 通过梯度下降来学习如何通过梯度下降来学习2 第二章&#xff1a;使用孪生网络进行人脸识别与音频视频2.1 什么是孪生神经网络孪生神经网…

机器学习与数据挖掘——数据预处理

如果有兴趣了解更多相关内容&#xff0c;欢迎来我的个人网站看看&#xff1a;瞳孔空间 一&#xff1a;关于数据预处理 在工程实践中&#xff0c;我们得到的数据会存在有缺失值、重复值等&#xff0c;在使用之前需要进行数据预处理。数据预处理没有标准的流程&#xff0c;通常…

Kaldi的简单介绍和基本使用说明

Kaldi的简单介绍和基本使用说明前言一、ASR简介1.语音识别系统特征提取&#xff1a;声学模型发音词典语言模型语音解码2. ASR项目二、Kaldi简介三、Kaldi项目的结构四、Kaldi的安装1. 安装依赖的几个系统开发库2. 安装依赖的第三方工具库3. 编译Kaldi代码配置Kaldi编译Kaldi五、…

Python-进程和线程

张钊*&#xff0c;沈啸彬*, 王旭* 李月&#xff0c;曹海艳&#xff0c; (淮北师范大学计算机科学与技术学院&#xff0c;淮北师范大学经济与管理学院&#xff0c;安徽 淮北) *These authors contributed to the work equllly and should be regarded as co-first authors. &a…

智能电网中需求响应研究(Matlab代码实现)

目录 1 概述 2 运行结果 ​编辑 ​编辑 3 参考文献 4 Matlab代码实现 1 概述 智能电网需求响应可以降低电网高峰用电需求、提高电网运行稳定性和可靠性&#xff0c;尤其是通过需求响应实现电网接纳间歇性可再生能源发电的能力。 需求响应的全球进展及产生的效益等情况在…

SDUT—Python程序设计实验1011(面向对象)

7-1 sdut-oop-2 Shift Dot(类和对象&#xff09; 给出平面直角坐标系中的一点&#xff0c;并顺序给出n个向量&#xff0c;求该点根据给定的n个向量位移后的位置。 设计点类Point&#xff0c;内含&#xff1a; &#xff08;1&#xff09;整型属性x和y&#xff0c;表示点的横坐标…