Shiro 框架基本使用

news2024/11/27 23:57:53

文章目录

  • Shiro框架介绍
  • Shiro 基本使用
    • SimpleAccountRealm
    • IniRealm
    • JdbcRealm
    • CustomRealm(自定义Realm)

Shiro框架介绍

Apache Shiro是一个强大且易用的Java安全框架,它执行身份验证、授权、密码和会话管理。Shiro框架通过其三个核心组件:Subject、SecurityManager和Realms,提供了一个通用的安全认证框架。

Shiro官方:http://shiro.apache.org

Shiro的核心架构图

image.png

Shiro 基本使用

认证流程:

image.png

授权流程:

image.png

SimpleAccountRealm

认证代码:

@Test
public void authen() {
    //认证的发起者(subject),   SecurityManager,   Realm
    //1. 准备Realm(基于内存存储用户信息)
    SimpleAccountRealm realm = new SimpleAccountRealm();
    realm.addAccount("admin", "admin", "超级管理员", "商家");

    //2. 准备SecurityManager
    DefaultSecurityManager securityManager = new DefaultSecurityManager();

    //3. SecurityManager和Realm建立连接
    securityManager.setRealm(realm);

    //4. subject和SecurityManager建立联系
    SecurityUtils.setSecurityManager(securityManager);

    //5. 声明subject
    Subject subject = SecurityUtils.getSubject();

    //6. 发起认证
    subject.login(new UsernamePasswordToken("admin", "admin"));
    // 如果认证时,用户名错误,抛出:org.apache.shiro.authc.UnknownAccountException异常
    // 如果认证时,密码错误,抛出:org.apache.shiro.authc.IncorrectCredentialsException:

    //7. 判断是否认证成功
    System.out.println(subject.isAuthenticated());

    //8. 退出登录后再判断
    //        subject.logout();
    //        System.out.println("logout方法执行后,认证的状态:" + subject.isAuthenticated());

    //9. 授权是在认证成功之后的操作!!!
    // SimpleAccountRealm只支持角色的授权
    System.out.println("是否拥有超级管理员角色:" + subject.hasRole("超级管理员"));
    subject.checkRole("商家");
    // check方法校验角色时,如果没有指定角色,会抛出异常:org.apache.shiro.authz.UnauthorizedException: Subject does not have role [角色信息]
}

IniRealm

基于文件存储用户名、密码、角色等信息

准备一个.ini文件,存储用户信息,并且IniRealm支持权限校验

[users]
username=password,role1,role2
admin=admin,超级管理员,运营
[roles]
role1=perm1,perm2
超级管理员=user:add,user:update,user:delete

代码:

@Test
public void authen(){
    //1. 构建IniRealm
    IniRealm realm = new IniRealm("classpath:shiro.ini");

    //2. 构建SecurityManager绑定Realm
    DefaultSecurityManager securityManager = new DefaultSecurityManager();
    securityManager.setRealm(realm);

    //3. 基于SecurityUtils绑定SecurityManager并声明subject
    SecurityUtils.setSecurityManager(securityManager);
    Subject subject = SecurityUtils.getSubject();

    //4. 认证操作
    subject.login(new UsernamePasswordToken("admin","admin"));

    //5. 角色校验
    // 超级管理员
    System.out.println(subject.hasRole("超级管理员"));
    subject.checkRole("运营");

    //6. 权限校验
    System.out.println(subject.isPermitted("user:update"));
    // 如果没有响应的权限,就抛出异常:UnauthorizedException: Subject does not have permission [user:select]
    subject.checkPermission("user:delete");
}

JdbcRealm

基于数据库存储用户名、密码、角色等信息。

用户认证、授权时推荐的表结构设计,经典五张表!

image.png

代码:

@Test
public void authen(){
    //1. 构建IniRealm
    JdbcRealm realm = new JdbcRealm();

    DruidDataSource dataSource = new DruidDataSource();
    dataSource.setDriverClassName("com.mysql.jdbc.Driver");
    dataSource.setUrl("jdbc:mysql:///shiro");
    dataSource.setUsername("root");
    dataSource.setPassword("root");
    realm.setDataSource(dataSource);

    realm.setPermissionsLookupEnabled(true);

    //2. 构建SecurityManager绑定Realm
    DefaultSecurityManager securityManager = new DefaultSecurityManager();
    securityManager.setRealm(realm);

    //3. 基于SecurityUtils绑定SecurityManager并声明subject
    SecurityUtils.setSecurityManager(securityManager);
    Subject subject = SecurityUtils.getSubject();

    //4. 认证操作
    subject.login(new UsernamePasswordToken("admin","admin"));

    //5. 授权操作(角色)
    System.out.println(subject.hasRole("超级管1理员"));

    //6. 授权操作(权限)
    System.out.println(subject.isPermitted("user:add"));

}

SQL构建代码

DROP TABLE IF EXISTS `roles_permissions`;
CREATE TABLE `roles_permissions` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `permission` varchar(128) NOT NULL,
  `role_name` varchar(128) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8mb4;

-- ----------------------------
-- Records of roles_permissions
-- ----------------------------
INSERT INTO `roles_permissions` VALUES ('1', 'user:add', '超级管理员');
INSERT INTO `roles_permissions` VALUES ('2', 'user:update', '超级管理员');
INSERT INTO `roles_permissions` VALUES ('3', 'user:select', '运营');

-- ----------------------------
-- Table structure for `users`
-- ----------------------------
DROP TABLE IF EXISTS `users`;
CREATE TABLE `users` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `username` varchar(32) NOT NULL,
  `password` varchar(32) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=2 DEFAULT CHARSET=utf8mb4;

-- ----------------------------
-- Records of users
-- ----------------------------
INSERT INTO `users` VALUES ('1', 'admin', 'admin');

-- ----------------------------
-- Table structure for `user_roles`
-- ----------------------------
DROP TABLE IF EXISTS `user_roles`;
CREATE TABLE `user_roles` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `role_name` varchar(128) NOT NULL,
  `username` varchar(32) NOT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=3 DEFAULT CHARSET=utf8mb4;

-- ----------------------------
-- Records of user_roles
-- ----------------------------
INSERT INTO `user_roles` VALUES ('1', '超级管理员', 'admin');
INSERT INTO `user_roles` VALUES ('2', '运营', 'admin');

CustomRealm(自定义Realm)

仿照JdbcRealm实现一个自定义的Realm对象

  • 声明POJO类,继承AuthorizingRealm
      public class CustomRealm extends AuthorizingRealm {
          ……………………
      }
    
  • 重写doGetAuthenticationInfo方法(认证)
      /**
       * 认证方法,只需要完成用户名校验即可,密码校验由Shiro内部完成
       * @param token  用户传入的用户名和密码
       * @return
       * @throws AuthenticationException
       */
      @Override
      protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
          //1. 基于Token获取用户名
          String username = (String) token.getPrincipal();
    
          //2. 判断用户名(非空)
          if(StringUtils.isEmpty(username)){
              // 返回null,会默认抛出一个异常,org.apache.shiro.authc.UnknownAccountException
              return null;
          }
    
          //3. 如果用户名不为null,基于用户名查询用户信息
          User user = this.findUserByUsername(username);
    
          //4. 判断user对象是否为null
          if(user == null){
              return null;
          }
    
          //5. 声明AuthenticationInfo对象,并填充用户信息
          SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user,user.getPassword(),"CustomRealm!!");
    
          //6. 返回info
          return info;
      }
    
      // 模拟数据库操作
      private User findUserByUsername(String username) {
          if("admin".equals(username)){
              User user = new User();
              user.setId(1);
              user.setUsername("admin");
              user.setPassword("admin");
              return user;
          }
          return null;
      }
    
  • 重写doGetAuthenticationInfo方法(密码加密加盐)
      {
          HashedCredentialsMatcher matcher = new HashedCredentialsMatcher();
          matcher.setHashAlgorithmName("MD5");
          matcher.setHashIterations(1024);
          this.setCredentialsMatcher(matcher);
      }
    
    
      /**
       * 认证方法,只需要完成用户名校验即可,密码校验由Shiro内部完成
       * @param token  用户传入的用户名和密码
       * @return
       * @throws AuthenticationException
       */
      @Override
      protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
          //1. 基于Token获取用户名
          String username = (String) token.getPrincipal();
    
          //2. 判断用户名(非空)
          if(StringUtils.isEmpty(username)){
              // 返回null,会默认抛出一个异常,org.apache.shiro.authc.UnknownAccountException
              return null;
          }
    
          //3. 如果用户名不为null,基于用户名查询用户信息
          User user = this.findUserByUsername(username);
    
          //4. 判断user对象是否为null
          if(user == null){
              return null;
          }
    
          //5. 声明AuthenticationInfo对象,并填充用户信息
          SimpleAuthenticationInfo info = new SimpleAuthenticationInfo(user,user.getPassword(),"CustomRealm!!");
          // 设置盐!
          info.setCredentialsSalt(ByteSource.Util.bytes(user.getSalt()));
          //6. 返回info
          return info;
      }
    
    
      // 模拟数据库操作
      private User findUserByUsername(String username) {
          if("admin".equals(username)){
              User user = new User();
              user.setId(1);
              user.setUsername("admin");
              user.setPassword("1ebc4dcaf1e21b814ece65f27531f1a9");
              user.setSalt("weruiothergjkdfnbgjkdfngjkdf");
              return user;
          }
          return null;
      }
    
  • 重写doGetAuthorizationInfo方法(授权)
    // 授权方法,授权是在认证之后的操作
    @Override
    protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
        //1. 获取认证用户的信息
        User user = (User) principals.getPrimaryPrincipal();
    
        //2. 基于用户信息获取当前用户拥有的角色。
        Set<String> roleSet = this.findRolesByUser();
    
        //3. 基于用户拥有的角色查询权限信息
        Set<String> permSet = this.findPermsByRoleSet(roleSet);
    
        //4. 声明AuthorizationInfo对象作为返回值,传入角色信息和权限信息
        SimpleAuthorizationInfo info = new SimpleAuthorizationInfo();
        info.setRoles(roleSet);
        info.setStringPermissions(permSet);
    
        //5. 返回
        return info;
    }
    
    private Set<String> findPermsByRoleSet(Set<String> roleSet) {
        Set<String> set = new HashSet<>();
        set.add("user:add");
        set.add("user:update");
        return set;
    }
    
    private Set<String> findRolesByUser() {
        Set<String> set = new HashSet<>();
        set.add("超级管理员");
        set.add("运营");
        return set;
    }
    

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

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

相关文章

网络爬虫-----爬虫的分类及原理

目录 爬虫的分类 1.通用网络爬虫&#xff1a;搜索引擎的爬虫 2.聚焦网络爬虫&#xff1a;针对特定网页的爬虫 3.增量式网络爬虫 4.深层网络爬虫 通用爬虫与聚焦爬虫的原理 通用爬虫&#xff1a; 聚焦爬虫&#xff1a; 爬虫的分类 网络爬虫按照系统结构和实现技术&#…

白鲸开源 X SelectDB 金融大数据联合解决方案公布!从源头解决大数据开发挑战

业务挑战与痛点 随着互联网技术的发展、云计算技术的成熟、人工智能技术的兴起和数字化经济的崛起&#xff0c;数据已成为企业的核心资产。在金融行业中&#xff0c;数字化已成为了支撑各类业务场景的核心力量&#xff0c;包括个人理财、企业融资、股票交易、保险理赔、贷款服…

【Java 基础篇】Java 文件及文件夹操作详解

在Java编程中&#xff0c;文件和文件夹操作是常见的任务之一。你可能需要读取、写入、创建、删除文件或文件夹&#xff0c;以及遍历文件系统中的内容。本文将详细介绍Java中如何执行这些常见的文件和文件夹操作&#xff0c;适用于初学者和基础用户。 1. 文件操作 读取文件内容…

如何显示并管理Python应用的数据?Kendo UI for Angular有妙招!

Angular是Python应用中进行数据管理和显示的一个很好的选择&#xff0c;如果能使用Kendo UI for Angular则可以更进一步。 PS&#xff1a;给大家推荐一个实用组件~Kendo UI for Angular是专业级的Angular UI组件库&#xff0c;不仅是将其他供应商提供的现有组件封装起来&#…

关于IDEA没有显示日志输出?IDEA控制台没有显示Tomcat Localhost Log和Catalina Log 怎么办?

问题描述&#xff1a; 原因是;CATALINA_BASE里面没有相关的文件配置。而之前学习IDEA的时候&#xff0c;把这个文件的位置改变了。导致&#xff0c;最后输出IDEA的时候&#xff0c;不会把日志也打印出来。 检查IDEA配置; D:\work_soft\tomcat_user\Tomcat10.0\bin 在此目录下&…

打造安全的Open RAN

O-RAN架构在为RAN网络引入更多灵活性和最佳实践的同时&#xff0c;也面临着更多的安全风险。本文分别从网元接口通信、RIC安全框架、云原生安全平台等角度全面介绍O-RAN架构在安全方面应该采取的措施。原文: Security in Open RAN 引言 Open RAN是O-RAN联盟在3GPP及其他标准的…

Eureka服务器注册

一。Eureka服务器注册 1.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://mav…

Windows10/11无线网卡WIFI驱动详细下载安装教程

官网下载WIFI驱动 《intel官网》 找到下载Windows 10 and Windows 11* WiFi package drivers 查看详细信息 下载对应操作系统的WIFI驱动 安装驱动&#xff0c;然后重启电脑即可。

SSM - Springboot - MyBatis-Plus 全栈体系(十)

第二章 SpringFramework 五、Spring AOP 面向切面编程 4. Spring AOP 框架介绍和关系梳理 AOP是一种区别于OOP的编程思维&#xff0c;用来完善和解决OOP的非核心代码冗余和不方便统一维护问题&#xff01;代理技术&#xff08;动态代理|静态代理&#xff09;是实现AOP思维编…

云原生之使用Docker部署Nas-Cab个人NAS平台

云原生之使用Docker部署Nas-Cab个人NAS平台 一、Nas-Cab介绍二、本地环境介绍2.1 本地环境规划2.2 本次实践介绍 三、本地环境检查3.1 检查Docker服务状态3.2 检查Docker版本3.3 检查docker compose 版本 四、下载Nas-Cab镜像五、部署Nas-Cab5.1 创建挂载目录5.2 创建Nas-Cab容…

前端开发之el-table 表头不换行且宽度自适应

element的table中动态添加表头并设置表头不换行 前言效果图element中使用代码 element-plus中使用:没有了h代码 前言 本次讲解的是elemen和element-plus来通过table的标签render-header来实现的 效果图 element中使用 代码 <template><div><el-table :data&q…

win10修改截图快捷键

用惯了截图快捷键&#xff0c;在新电脑上截图不方便&#xff0c;win10自带截图功能&#xff0c;修改一下系统设置就能使用 点击左下角开始图标&#xff0c;找到Windows 附件&#xff0c;鼠标放到截图工具图标上 点击鼠标右键&#xff0c;选择更多&#xff0c;打开文件位置 跳转…

【排障记录】扩展坞USB 3.0能用而2.0不能用

一、症状表现 日常使用小米的一个扩展坞连接笔记本&#xff0c;平时用来插U盘&#xff0c;没有什么问题&#xff0c;但是今天插了鼠标键盘&#xff0c;发现根本不识别 二、排查过程 目前的连接结构 笔记本C口→type-C延长线→扩展坞A→设备 1.排查笔记本故障 将键盘鼠标插…

MYSQL索引——B+树讲解

B-/B树看 MySQL索引结构 B-树 B-树,这里的 B 表示 balance( 平衡的意思),B-树是一种多路自平衡的搜索树.它类似普通的平衡二叉树&#xff0c;不同的一点是B-树允许每个节点有更多的子节点。下图是 B-树的简化图. B-树有如下特点: 所有键值分布在整颗树中&#xff1b; 任何一…

Dubbo3应用开发—XML形式的Dubbo应用开发和SpringBoot整合Dubbo开发

Dubbo3程序的初步开发 Dubbo3升级的核心内容 易⽤性 开箱即⽤&#xff0c;易⽤性⾼&#xff0c;如 Java 版本的⾯向接⼝代理特性能实现本地透明调⽤功能丰富&#xff0c;基于原⽣库或轻量扩展即可实现绝⼤多数的 微服务治理能⼒。更加完善了多语言支持&#xff08;GO PYTHON R…

vue基础知识十四:说说你对vue的mixin的理解,有什么应用场景?

一、mixin是什么 Mixin是面向对象程序设计语言中的类&#xff0c;提供了方法的实现。其他类可以访问mixin类的方法而不必成为其子类 Mixin类通常作为功能模块使用&#xff0c;在需要该功能时“混入”&#xff0c;有利于代码复用又避免了多继承的复杂 Vue中的mixin 先来看一…

【关于RHCE考试和准备看这一篇就够了】

一、文章大纲 认证机构 课程体系 面向人群 证书有效期 备考学习周期 考试内容 证书领取 证书样例 二、认证机构 RHCE全称为红帽认证工程师&#xff08;Red Hat Certified Engineer&#xff09;&#xff0c;其认证机构为红帽。红帽可以说是Linux发行版中的龙头老大&am…

Android 数据库封装(SQLite)

Android 数据库操作&#xff08;SQLite&#xff09; Android 数据库操作&#xff08;SQLite&#xff09;动态预览使用初始化生成表实体类插入数据批量插入删除数据删除全部修改数据查找&#xff08;列表&#xff09;查找&#xff08;单条&#xff09;条件查找&#xff08;列表&…

【去除若依首页】有些小项目不需要首页,去除方法

第一步 // // // // // // // // // // // // // // // // // // 修改登录页 Login.vue 中 大概144行 &#xff0c;注释掉原有跳转。替换为自己的跳转路径 // // // // // // // // // // // // // this.$router.push({ path: this.redirect || …

windows英伟达nvidia显卡驱动安装教程

文章目录 查看版本驱动下载驱动安装查看安装结果 查看版本 之前我的电脑预安装了nvidia的显卡驱动&#xff0c;通过nvidia-smi命令发现驱动版本是Driver Version&#xff1a;417.98&#xff0c;CUDA Version&#xff1a;10.0&#xff0c;目前的驱动和CUDA支持的已经是4年前的版…