SpringBoot 整合 Shiro 权限框架

news2025/2/23 12:35:42

目录

  • Shiro概述
    • Shiro介绍
    • 基本功能
    • Shiro架构
  • SpringBoot整合Shiro
    • 环境搭建
    • 登录、授权、角色认证实现
      • 自定义实现 Realm
      • Shiro配置类
      • controller代码
      • 权限异常处理
    • 多个 realm 的认证策略设置
    • 会话管理
      • 获得session方式

Shiro概述

Shiro介绍

Apache Shiro 是一个功能强大且易于使用的 Java 安全(权限)框架。Shiro 可以完成:认证授权加密会话管理与 Web 集成缓存 等。借助 Shiro 您可以快速轻松地保护任何应用程序——从最小的移动应用程序到最大的 Web 和企业应用程序。
在这里插入图片描述

官方网址: https://shiro.apache.org/

基本功能

在这里插入图片描述

  • Authentication:身份认证/登录,验证用户是不是拥有相应的身份;
  • Authorization:授权,即权限验证,验证某个已认证的用户是否拥有某个权限;
  • Session Manager:会话管理,即用户登录后就是一次会话,在没有退出之前,它的所有 信息都在会话中;会话可以是普通 JavaSE 环境,也可以是 Web 环境的;
  • Cryptography:加密,保护数据的安全性,如密码加密存储到数据库,而不是明文存储;
  • Web Support:Web 支持,可以非常容易的集成到 Web 环境;
  • Caching:缓存,比如用户登录后,其用户信息、拥有的角色/权限不必每次去查,这样可 以提高效率;
  • Concurrency:Shiro 支持多线程应用的并发验证,即如在一个线程中开启另一个线程,能把权限自动传播过去;、
  • Testing:提供测试支持;
  • Run As:允许一个用户假装为另一个用户(如果他们允许)的身份进行访问;
  • Remember Me:记住我,这个是非常常见的功能,即一次登录后,下次再来的话不用登录了

Shiro架构

在这里插入图片描述

  • Subject:任何可以与应用交互的“用户”;
  • SecurityManager :相当于 SpringMVC 中的 DispatcherServlet;是 Shiro 的心脏; 所有具体的交互都通过 SecurityManager 进行控制;它管理着所有 Subject、且负责进 行认证、授权、会话及缓存的管理。
  • Authenticator:负责 Subject 认证,是一个扩展点,可以自定义实现;可以使用认证 策略(Authentication Strategy),即什么情况下算用户认证通过了;
  • Authorizer:授权器、即访问控制器,用来决定主体是否有权限进行相应的操作;即控 制着用户能访问应用中的哪些功能;
  • Realm:可以有 1 个或多个 Realm,可以认为是安全实体数据源,即用于获取安全实体 的;可以是 JDBC 实现,也可以是内存实现等等;由用户提供;所以一般在应用中都需要 实现自己的 Realm;
  • SessionManager:管理 Session 生命周期的组件;而 Shiro 并不仅仅可以用在 Web 环境,也可以用在如普通的 JavaSE 环境
  • CacheManager:缓存控制器,来管理如用户、角色、权限等的缓存的;因为这些数据基本上很少改变,放到缓存中后可以提高访问的性能
  • Cryptography:密码模块,Shiro 提高了一些常见的加密组件用于如密码加密/解密。

SpringBoot整合Shiro

环境搭建

引入依赖

<dependency>
 <groupId>org.apache.shiro</groupId>
 <artifactId>shiro-spring-boot-web-starter</artifactId>
 <version>1.9.0</version>
 </dependency>

指定登录路径

shiro:
 loginUrl: /user/login

创建数据库
user表
在这里插入图片描述
role表
在这里插入图片描述
user_role表
在这里插入图片描述
permissions表
在这里插入图片描述
role_permissions表
在这里插入图片描述

登录、授权、角色认证实现

省略Mybatis查询数据库代码

自定义实现 Realm

@Component("authorizer")
public class MyRealm extends AuthorizingRealm {

    @Autowired
    private UserService userService;


    /**
     * 自定义授权方法
     * @param principalCollection
     * @return
     */
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {
        //1 创建对象,存储当前登录的用户的权限和角色
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        //2 获取当前用户身份信息
        String name = principalCollection.getPrimaryPrincipal().toString();
        List<String> roles = userService.getUserRoles(name);
        //3 存储角色
        info.addRoles(roles);
        //4 获取用户角色的权限信息
        List<String> permissions=new ArrayList<>();
        for (String role : roles) {
            List<String> ps = userService.getUserPermission(role);
            permissions.addAll(permissions);
        }
        //5 存储权限信息
        info.addStringPermissions(permissions);
        //6 返回
        return info;
    }

    /**
     * 自定义登录方法
     * @param authenticationToken
     * @return
     * @throws AuthenticationException
     */
    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {
        //获取用户身份信息
        String name = authenticationToken.getPrincipal().toString();
        //查询用户信息
        User user = userService.getUserByName(name);
        if (user!=null){
            AuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(
                    name,//用户名
                    user.getPwd(),//密码
                    ByteSource.Util.bytes("salt"),//加盐字符
                    getName()//realm名称
            );
            return authenticationInfo;
        }
        return null;
    }

}

Shiro配置类

@Configuration
public class ShiroConfig {

    //配置自定义Realm
    @Bean
    public MyRealm myRealm(){
        return new MyRealm();
    }

    //配置 SecurityManager
    @Bean
    public DefaultWebSecurityManager defaultWebSecurityManager(){
        //1 创建 defaultWebSecurityManager 对象
        DefaultWebSecurityManager manager = new DefaultWebSecurityManager();
        //2 创建加密对象,并设置相关属性
        HashedCredentialsMatcher matcher = new HashedCredentialsMatcher();
        //2.1 采用 md5 加密
        matcher.setHashAlgorithmName("md5");
        //2.2 迭代加密次数
        matcher.setHashIterations(3);
        //3 将加密对象存储到 myRealm 中
        myRealm().setCredentialsMatcher(matcher);
        //4 将 myRealm 存入 defaultWebSecurityManager 对象
        manager.setRealm(myRealm());
        //5 返回 defaultWebSecurityManager 对象
        return manager;
    }

    //配置 Shiro 内置过滤器拦截范围
    @Bean
    public DefaultShiroFilterChainDefinition shiroFilterChainDefinition(){
        DefaultShiroFilterChainDefinition definition = new DefaultShiroFilterChainDefinition();
        //设置不认证可以访问的资源
        definition.addPathDefinition("/user/login","anon");
        //配置退出过滤器
        definition.addPathDefinition("/logout","logout");
        //设置需要进行登录认证的拦截范围
        definition.addPathDefinition("/**","authc");
        return definition;
    }
}

controller代码

@RestController
@RequestMapping("/user")
@ResponseBody
public class UserController {

    @PostMapping(path = "/login",produces = "application/json")
    public String login(@RequestBody User user){
        try {
            //1 获取 Subject 对象
            Subject subject = SecurityUtils.getSubject();
            //2 封装请求数据到 token 对象中
            UsernamePasswordToken token = new UsernamePasswordToken(user.getName(),user.getPwd());
            subject.login(token);
            return "登录成功!";
        }
        catch (LockedAccountException e){
            return "账号封禁";

        }
        catch (UnknownAccountException e) {
            e.printStackTrace();
            return  "用户不存在";
        }
        catch (IncorrectCredentialsException e) {
            e.printStackTrace();
            return  "密码错误";
        }
        catch (AuthenticationException e) {
            e.printStackTrace();
            return "登录失败!";
        }
    }

    //登录认证验证角色
    @RequiresRoles("admin")
    @GetMapping("/roles")
    public String userLoginRoles() {
        return "验证角色成功";
    }

    //登录认证验证权限
    @RequiresPermissions("user:delete")
    @GetMapping("/permissions")
    public String userLoginPermissions() {
        return "验证权限成功";
    }
}

权限异常处理

@ControllerAdvice
@ResponseBody
public class PermissionsException {


    @ExceptionHandler(UnauthorizedException.class)
    public String unauthorizedException(Exception ex){
        return "无权限";
    }

}

多个 realm 的认证策略设置

AuthenticationStrategy class描述
AtLeastOneSuccessfulStrategy只要有一个(或更多)的 Realm 验证成功,那么认证将视为成功
FirstSuccessfulStrategy第一个 Realm 验证成功,整体认证将视为成功,且后续 Realm 将被忽略
AllSuccessfulStrategy所有 Realm 成功,认证才视为成功

ModularRealmAuthenticator 内置的认证策略默认实现是 AtLeastOneSuccessfulStrategy 方式。

//配置 SecurityManager
@Bean
public DefaultWebSecurityManager defaultWebSecurityManager(){
 //1 创建 defaultWebSecurityManager 对象
 DefaultWebSecurityManager defaultWebSecurityManager = new 
 DefaultWebSecurityManager();
 //2 创建认证对象,并设置认证策略
 ModularRealmAuthenticator modularRealmAuthenticator = new 
 ModularRealmAuthenticator();
 modularRealmAuthenticator.setAuthenticationStrategy(new 
 AllSuccessfulStrategy());
 
defaultWebSecurityManager.setAuthenticator(modularRealmAuthenticator);
 //3 封装 myRealm 集合
 List<Realm> list = new ArrayList<>();
 list.add(myRealm1);
 list.add(myRealm2);
 //4 将 myRealm 存入 defaultWebSecurityManager 对象
 defaultWebSecurityManager.setRealms(list);
 //5 返回
 return defaultWebSecurityManager;

会话管理

SessionManager由SecurityManager管理。Shiro提供了三种实现:

  • DefaultSessionManager:用于JavaSE环境
  • ServletContainerSessionManager:用于web环境,直接使用Servlet容器的会话
  • DefaultWebSessionManager:用于web环境,自己维护会话(不使用Servlet容器的
    会话管理)

获得session方式

Session session = SecurityUtils.getSubject().getSession();
session.setAttribute(“key”,”value”)
  • Controller 中的 request,在 shiro 过滤器中的 doFilerInternal 方法,被包装成
    ShiroHttpServletRequest。
  • SecurityManager 和 SessionManager 会话管理器决定 session 来源于ServletRequest还是由 Shiro 管理的会话。无论是通过 request.getSession 或subject.getSession 获取到 session,操作session,两者都是等价的。

学习内容来自尚硅谷

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

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

相关文章

力扣(LeetCode)42. 接雨水(C++)

栈 明确目标——计算接雨水的总量。 可以想到一层一层的接雨水。和算法结合&#xff0c;介绍思想 &#xff1a; 遍历柱子&#xff0c;栈 stkstkstk 维护降序高度的柱子&#xff0c;如果出现升序&#xff0c;说明形成凹槽&#xff0c;计算凹槽能接的雨水&#xff0c;加入答案。…

Java强软弱虚引用和ThreadLocal工作原理(一)

一、概述 本篇文章先引入java的四种引用在android开发中的使用&#xff0c;然后结合弱引用来理解ThreadLocal的工作原理。 二、JVM名词介绍 在提出四种引用之前&#xff0c;我们先提前说一下 Java运行时数据区域 虚拟机栈 堆 垃圾回收机制 这四个概念。 2.1 java运行时数据…

freeswitch通过limit限制cps

概述 freeswitch在业务开发中有极大的便利性&#xff0c;因为fs内部实现了很多小功能&#xff0c;这些小功能组合在一起&#xff0c;通过拨号计划就可以实现很多常见的业务功能。 在voip云平台的开发中&#xff0c;我们经常会碰到资源的限制&#xff0c;有外部线路资源方面的…

Linux环境下安装并使用使用Git命令实现文件上传

⭐️前面的话⭐️ 本篇文章将介绍在Linux环境下安装Git并使用Git实现代码上传到gitee&#xff0c;上传操作的核心就是三把斧&#xff0c;一是add&#xff0c;二是commit&#xff0c;三是push&#xff0c;此外还会简单介绍一下.gitignore配置文件的作用。 &#x1f4d2;博客主页…

【broadcast-service】一个轻量级Python发布订阅者框架

本文节选至本人博客&#xff1a;https://www.blog.zeeland.cn/archives/broadcast-service-description Introduction 前两天在Python最佳实践-构建自己的第三方库文章中介绍了自己构建的一个轻量级的Python发布订阅者框架&#xff0c;今天来简单介绍一下。 项目地址&#xf…

不同的量化交易软件速度差距大吗?

哪家券商的软件交易速度快&#xff1f;那个平台有极速柜台系统&#xff1f;成为了一个热门的话题&#xff0c;我来说下我的看法。其实呢&#xff0c;大部分的主流券商速度都是差不多的&#xff0c;否则的话&#xff0c;那速度有差距大家肯定都会冲向最快的那一家了。极速柜台系…

查看mysql的版本

1. mysql --version linux下使用命令&#xff1a; mysql --version 2. mysql -V 没有连接到MySQL服务器&#xff0c;就想查看MySQL的版本。打开cmd&#xff0c;切换至mysql的bin目录&#xff0c;运行下面的命令即可&#xff1a; 2.1 mysql -V e:\mysql\bin> mysql -V mys…

k8s编程operator——client-go中的informer

文章目录1、介绍1.1 简单使用1.2 List & Watch1.3 informer简介2、store2.1 ThreadSafeMap建立索引&#xff1a;threadSafeMap源码分析&#xff1a;2.2 Indexer2.3 DeltaFIFO3、reflector3.1 Reflector的定义3.2 Reflector的创建3.3 Reflector的循环执行3.4 List操作3.5 Wa…

JAVA 之 Spring框架学习 1:Springの初体验 IOC DI 注入 案例

Spring技术是JavaEE开发必备技能&#xff0c;企业开发技术选型命中率>90% 专业角度 简化开发&#xff0c;降低企业级开发的复杂性 框架整合&#xff0c;高效整合其他技术&#xff0c;提高企业级应用开发与运行效率 1.学习Spring框架设计思想 2.学习基础操作&#xff0c;思…

数据结构之选择排序(堆排序)

选择排序 选择排序分为两种一个是堆排序 一个是简单选择排序 简单选择排序 就是从头到尾扫描一遍待排序元素找出最小的 最小的之前的数的往后一位&#xff0c;第一个空间空出来 把最小的元素存入 然后从第二个空间开始变为待排序元素 最后一个元素不用处理 代码实现 算法性…

【python】根据自定义曲线函数进行拟合

【参考】 官网 curve_fit示例与评估&#xff1a;拟合curve_fit使用矫正的R^2评估非线性模型&#xff1a;拟合评估其他&#xff1a; curve_fit()实现任意形式的曲线拟合-csdn拟合优度r^2-csdn 官网示例 拟合函数&#xff1a; f(x)ae−bxcf(x)ae^{-bx}cf(x)ae−bxc import m…

Git——IDEA集成Git(详细)

目录 一、配置Git忽略文件 1.1 为什么忽略&#xff1f; 1.2 怎么忽略&#xff1f; 二. IDEA定位Git程序&#xff08;准备环境&#xff09; 三、IDEA操作Git 3.1 初始化Git本地库、添加暂存区、提交本地库 3.2 切换版本 3.3 创建分支 3.4 切换分支 3.5 合并分支 3.5.1…

存储模块 --- Cache

Cache 高速缓冲存储器 内存一般采用SDRAM芯片&#xff0c;对内存的访问肯定是不及CPU的速度的&#xff0c;通常说内存访问要比CPU的速度慢的多。也就是说内存拖后腿了。 CPU访问内存并不是完全随机的。 在某个时间段内&#xff0c;CPU总是访问当前内存地址的相邻内存地址&…

数理统计笔记5:参数估计-区间估计

引言 数理统计笔记的第5篇先介绍了参数估计的区间估计。包括单总体均值、单总体比例、单总体方差以及两总体均值之差、两总体方差之比几种常见的情况。 引言总体均值的置信区间&#xff08;σ2\sigma^2σ2已知&#xff09;-Z法总体均值的置信区间&#xff08;σ2\sigma^2σ2未知…

【Call for papers】SP-2023(CCF-A/网络与信息安全/2022年12月2日截稿)

文章目录1.会议信息2.时间节点Since 1980, the IEEE Symposium on Security and Privacy has been the premier forum for presenting developments in computer security and electronic privacy, and for bringing together researchers and practitioners in the field. The…

whylogs工具库的工业实践!机器学习模型流程与效果监控 ⛵

&#x1f4a1; 作者&#xff1a;韩信子ShowMeAI &#x1f4d8; 机器学习实战系列&#xff1a;https://www.showmeai.tech/tutorials/41 &#x1f4d8; 本文地址&#xff1a;https://www.showmeai.tech/article-detail/395 &#x1f4e2; 声明&#xff1a;版权所有&#xff0c;转…

如何理解相位噪声与时间抖动的关系?

每当介绍相位噪声测试方案时&#xff0c;都会提到时间抖动&#xff0c;经常提到二者都是表征信号短期频率稳定度的参数&#xff0c;而且是频域和时域相对应的参数。正如题目所示&#xff0c;相位噪声与时间抖动有着一定的关系&#xff0c;那么相噪是与哪种类型的抖动相对应&…

葡萄糖-聚乙二醇-醛基/羟基 Glucose-PEG-CHO/OH

葡萄糖-聚乙二醇-醛基Glucose-PEG-CHO 羰基中的一个共价键跟氢原子相连而组成的一价原子团&#xff0c;叫做醛基&#xff0c;醛基结构简式是-CHO&#xff0c;醛基是亲水基团&#xff0c;因此有醛基的有机物&#xff08;如乙醛等&#xff09;有一定的水溶性。 葡萄糖-聚乙二醇…

ILRuntime热更的小技巧

文章目录前因后果前因 因为ILRuntime热更项目直接打包出来的DLL不能放置到AssetBundle里面打包所以我看网上的代码都是读取DLL的bytes然后放置到一个text文件里面后缀是bytes public class DefaultPath {public static string ProjectRootPath Environment.CurrentDirectory…

超市便利店微信小程序引流拉新_分享超市便利店微信小程序开发的作用

作为消费主力的年轻人&#xff0c;习惯用手机。习惯在手机下单&#xff0c;享受足不出户的方便快捷。 再加上疫情反复&#xff0c;线上购物&#xff0c;无接触配送显得更安全卫生。 再这样的市场环境下&#xff0c;做一个线上的超市小程序&#xff0c;就能解决很多问题&…