Shiro教程(一):入门概述与基本使用

news2024/11/27 15:52:56

Shiro

第一章:入门概述

1.1 Shiro是什么

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

https://shiro.apache.org/

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

1.2 为什么使用Shiro

自2003年以来,框架格局发生了相当大的变化,因此今天仍然有很多系统在使用Shiro。这与Shiro的特性密不可分。

易于使用:使用Shiro构建系统安全框架非常简单。就算第一次接触也能快速掌握。

全面:Shiro包含系统完全框架需要的功能,满足安全需求的一站式服务。

灵活:Shiro可以在任何应用程序环境中工作。虽然它可以在Web、EJB和IoC环境中工作,但不需要依赖它们。Shiro也没有强制要求任何规范,甚至没有很多依赖项。

强力支持Web:Shiro具有出色的Web应用程序支持,可以基于应用程序URL和Web协议(例如REST)创建灵活的安全策略,同时还提供一组JSP库来控制页面输出。

兼容性强:Shiro的设计模式使其易于与其他框架和应用程序集成。Shiro与Spring、Grails、Wicket、Tapestry、Mule、Apache Camel、Vaadin等框架无缝集成。

社区支持:Shiro是Apache软件基金会的一个开源项目,有完备的社区支持,文档支持。如果需要,像Katasoft这样的商业公司也会提供专业的支持和服务。

1.3 Shiro与SpringSecurity的对比

  1. SpringSecurity基于Spring开发,项目若使用Spring作为基础,配合SpringSecurity做权限更加方便,而Shiro需要和Spring进行整合开发;
  2. SpringSecurity功能比Shiro更加丰富,例如安全维护方面;
  3. SpringSecurity社区资源相对比Shiro更加丰富;
  4. Shiro的配置和使用比较简单,SpringSecurity上手复杂些;
  5. Shiro依赖性低,不需要任何框架和容器,可以独立运行。SpringSecurity依赖Spring容器;
  6. Shiro不仅仅可以使用Web中,它可以工作在任何应用环境中。在集群会话时Shiro最重要的一个好处或许就是它的会话独立于容器的。

1.4 基本功能

  • 认证登录
  • 授权、权限验证
  • 会话管理
  • 加密功能
  • ···

第二章:基本使用

2.1 环境准备

1、Shiro不依赖容器,直接创建maven工程即可。

创建maven工程

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-35seCd2A-1689075634370)(C:/Users/Administrator/AppData/Roaming/Typora/typora-user-images/image-20221014105855921.png)]

添加module

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3eETQRQt-1689075634370)(C:/Users/Administrator/AppData/Roaming/Typora/typora-user-images/image-20221014105944954.png)]

2、添加依赖

    <dependencies>
        <dependency>
            <groupId>org.apache.shiro</groupId>
            <artifactId>shiro-core</artifactId>
            <version>1.9.0</version>
        </dependency>

        <dependency>
            <groupId>commons-logging</groupId>
            <artifactId>commons-logging</artifactId>
            <version>1.2</version>
        </dependency>
    </dependencies>

2.2 INI文件

Shiro获取权限相关信息可以通过数据库获取,也可以通过ini配置文件获取。

1、创建ini文件

src/main/resources/下创建shiro.ini文件

[users]
zhangsan=z3
lisi=l4

2.3 登录认证

1、登录认证概念

  • 身份验证:一般需要提供如身份ID等一些标识信息来表明登陆者的身份,如提供email,用户名,密码等。
  • 在shiro中,用户需要提供principals(身份)和credentials(证明)给shiro,从而应用能验证用户身份。
  • principals:身份,即主体的标识属性,可以是任何属性,如用户名、密码、邮箱,唯一即可。一个主体可以有多个principals,但只有一个Primary principals。一般是用户名、邮箱、手机号。
  • credentials:证明,即只有主体知道的安全值,如密码、数字证书等。
  • 最常见的principals和credentials组合就是用户名和密码。

2、登录认证基本流程

  1. 收集用户身份/凭证,即用户名/密码。
  2. 调用Subject.login进行登录,如果失败将得到相应的AuthenticationException异常,根据异常提示用户错误信息;否则登录成功。
  3. 创建自定义的Realm类,继承org.apache.shiro.realm.AuthenticatingRealm类,实现doGetAuthenticationInfo()方法。

3、登录认证实例

创建包com/wang/shirotest,然后包下新建ShiroRun测试类

package com.wang.shirotest;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.config.IniSecurityManagerFactory;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.subject.Subject;


public class ShiroRun {
    public static void main(String[] args) {
        // 1 初始化获取SecurityManager
        IniSecurityManagerFactory factory = new IniSecurityManagerFactory("classpath:shiro.ini");
        SecurityManager securityManager = factory.getInstance();
        SecurityUtils.setSecurityManager(securityManager);
        // 2 获取Subject对象
        Subject subject = SecurityUtils.getSubject();
        // 3 创建token对象,web应用用户名密码从页面传递
        AuthenticationToken token = new UsernamePasswordToken("zhangsan", "z3");
        // 4 完成登录
        try {
            subject.login(token);
            System.out.println("登录成功");
        } catch (UnknownAccountException e) {
            e.printStackTrace();
            System.out.println("用户不存在");
        } catch (IncorrectCredentialsException e) {
            e.printStackTrace();
            System.out.println("密码错误");
        } catch (AuthenticationException e) {
            e.printStackTrace();
        }
    }
}

①登录成功
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-eZwehhkB-1689075634370)(C:/Users/Administrator/AppData/Roaming/Typora/typora-user-images/image-20221015073506335.png)]
②用户不存在
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-64kTy3JU-1689075634371)(C:/Users/Administrator/AppData/Roaming/Typora/typora-user-images/image-20221015073544075.png)]
③密码错误
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-s3GNJonm-1689075634371)(C:/Users/Administrator/AppData/Roaming/Typora/typora-user-images/image-20221015073609125.png)]

2.4 角色、授权

1、授权概念

  • 授权:也叫访问控制,即在应用中控制谁访问哪些资源。在授权中需要了解几个关键对象:主体(Subject)、资源(Resource)、权限(Permission)、角色(Role)。
  • 主体(Subject):访问应用的用户,在Shiro中使用Subject代表该用户,用户只有授权,才能访问相应的资源。
  • 资源(Resource):在应用中用户可以访问的URL,比如查看/编辑某些数据。用户只有授权后才能访问。
  • 权限(Permission):安全策略中的原子授权单位,通过权限我们可以表示在应用中用户有没有操作某个资源的权力。即权限表示在应用中用户能不能访问某个资源
  • Shiro支持粗粒度权限(如用户模块的所有权限)和细粒度权限(操作某个用户的权限,即实例级别的)
  • 角色(Role):权限的集合,一般情况下会赋予用户角色而不是权限,即这样用户可以拥有一组权限,赋予权限时比较方便。典型的如:项目经理、技术总监、开发工程师。

2、授权方式

  • 编程式:通过写if/else授权代码完成

    • if(subject.hasRole('admin')){
          // 有权限
      } else {
          // 无权限
      }
      
  • 注解式:通过执行的Java方法上放置相应的注解完成,没有权限时将抛出相应的异常。

    • @RequiresRoles("admin")
      public void hello(){
          // 有权限
      }
      
  • JSP/GSP标签:在JSP/GSP页面通过相应的标签完成。

    • <shiro:hasRole name="admin">
      	<!--有权限-->
      </shiro:hasRole>
      

3、授权流程

  1. 首先调用Subject.isPermitted*/hasRole*接口,其会委托给SecurityManager,而 SecurityManager接着会委托给 Authorizer
  2. Authorizer是真正的授权者,如果调用如isPermitted(“user:view”),其首先会通 过PermissionResolver把字符串转换成相应的Permission实例;
  3. 在进行授权之前,其会调用相应的Realm获取Subject相应的角色/权限用于匹配传入 的角色/权限;
  4. Authorizer会判断Realm的角色/权限是否和传入的匹配,如果有多个Realm,会委托给ModularRealmAuthorizer进行循环判断,如果匹配如isPermitted*/hasRole* 会返回 true,否则返回false表示授权失败

4、授权实例

(1)角色判断

修改.ini文件,给用户添加角色

[users]
zhangsan=z3, role1, role2
lisi=l4

添加代码,判断用户是否有此角色

try {
            subject.login(token);
            System.out.println("登录成功");
            // 5 判断角色
            boolean hasRole = subject.hasRole("role1");
            System.out.println("是否拥有此角色:" + hasRole);
        }

运行代码

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

(2)判断权限信息

.ini文件添加角色权限信息

[roles]
role1=user:insert,user:select

try中添加以下代码

 // 6 判断权限
            boolean hasPermit = subject.isPermitted("user:insert");
            System.out.println("是否拥有此权限:" + hasPermit);

运行代码

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

也可以使用checkPermission()方法检查用户是否拥有某个权限

// 也可以用checkPermission方法,但没有返回值,没有权限直接抛异常
subject.checkPermission("user:insert111");

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

5、完整代码

package com.wang.shirotest;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.*;
import org.apache.shiro.config.IniSecurityManagerFactory;
import org.apache.shiro.mgt.SecurityManager;
import org.apache.shiro.subject.Subject;


public class ShiroRun {
    public static void main(String[] args) {
        // 1 初始化获取SecurityManager
        IniSecurityManagerFactory factory = new IniSecurityManagerFactory("classpath:shiro.ini");
        SecurityManager securityManager = factory.getInstance();
        SecurityUtils.setSecurityManager(securityManager);
        // 2 获取Subject对象
        Subject subject = SecurityUtils.getSubject();
        // 3 创建token对象,web应用用户名密码从页面传递
        AuthenticationToken token = new UsernamePasswordToken("zhangsan", "z3");
        // 4 完成登录
        try {
            subject.login(token);
            System.out.println("登录成功");
            // 5 判断角色
            boolean hasRole = subject.hasRole("role1");
            System.out.println("是否拥有此角色:" + hasRole);
            // 6 判断权限
            boolean hasPermit = subject.isPermitted("user:insert");
            System.out.println("是否拥有此权限:" + hasPermit);
            // 也可以用checkPermission方法,但没有返回值,没有权限直接抛异常
            subject.checkPermission("user:insert111");
        } catch (UnknownAccountException e) {
            e.printStackTrace();
            System.out.println("用户不存在");
        } catch (IncorrectCredentialsException e) {
            e.printStackTrace();
            System.out.println("密码错误");
        } catch (AuthenticationException e) {
            e.printStackTrace();
        }
    }
}

2.5 Shiro加密

实际系统开发中,一些敏感信息需要进行加密,比如用户的密码。Shiro内嵌很多常用的加密算法,比如MD5加密。Shiro可以很简单的使用信息加密。

1、使用Shiro进行密码加密

可以使用普通加密和带盐加密

package com.wang.shirotest;


import org.apache.shiro.crypto.hash.Md5Hash;

public class ShiroMD5 {
    public static void main(String[] args) {
        // 密码明文
        String password = "z3";
        // 使用MD5加密
        Md5Hash md5Hash = new Md5Hash(password);
        System.out.println("MD5加密后的密码=" + md5Hash);
        // 带盐的MD5加密,盐就是在密码明文后拼接新字符串,然后在进行加密
        Md5Hash md5Hash1 = new Md5Hash(password, "salt");
        System.out.println("带盐的MD5加密后的密码=" + md5Hash1);
    }
}

打印加密后的密码

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

2、多次加密

Md5Hash md5Hash2 = new Md5Hash(password, "salt", 3);
System.out.println("带盐的MD5的3次加密后的密码=" + md5Hash2);

加密后的密码更难被破解

带盐的MD5的3次加密后的密码=7174f64b13022acd3c56e2781e098a5f

使用父类进行加密

 // 使用父类进行加密
        SimpleHash simpleHash = new SimpleHash("MD5", password, "salt", 3);
        System.out.println("父类的带盐的MD5的3次加密后的密码=" + simpleHash.toHex());

打印结果可以看到,盐相同时两次加密3次之后的密码是相同的

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

2.6 Shiro自定义登录认证

Shiro默认的登录认证是不带加密的,如果想要实现加密认证需要自定义登录认证,自定义Realm。

1、认证实现

package com.wang.shirotest;

import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.realm.AuthenticatingRealm;
import org.apache.shiro.util.ByteSource;


/**
 * @author Administrator
 */
public class MyRealm extends AuthenticatingRealm {

    // 自定义登录认证方法,Shiro的login方法底层会调用该类的认证方法进行认证
    // 需要配置自定义的Realm生效,在ini文件中可以配置
    // 该方法只是获取进行对比的信息,认证逻辑还是按照Shiro底层认证逻辑完成

    @Override
    protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {

        // 1、获取身份信息
        String principal = authenticationToken.getPrincipal().toString();
        System.out.println("认证用户信息 = " + principal);
        // 2、获取凭证信息
        String password = new String((char[])authenticationToken.getCredentials());
        System.out.println("密码 = " + password);
        // 3、访问数据库获取用户信息
        if(principal.equals("zhangsan")){
            // 3.1、数据库中存的是加盐迭代3次之后的密码
            String passwordInfo = "7174f64b13022acd3c56e2781e098a5f";
            // 4、创建封装校验逻辑的对象,封装数据返回
            AuthenticationInfo info = new SimpleAuthenticationInfo(
                    authenticationToken.getPrincipal(),
                    passwordInfo,
                    ByteSource.Util.bytes("salt"),
                    authenticationToken.getPrincipal().toString()
            );
            return info;
        }

        return null;
    }
}

2、在Shiro.ini中添加配置信息

[main]
md5CredentialsMatcher=org.apache.shiro.authc.credential.Md5CredentialsMatcher
md5CredentialsMatcher.hashIterations=3

myrealm=com.wang.shirotest.MyRealm
myrealm.credentialsMatcher=$md5CredentialsMatcher
securityManager.realms=$myrealm

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

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

相关文章

用于3D渲染和平面设计应该怎么选择显卡?

首先了解快速解决3D渲染本地配置不足&#xff0c;节省硬件成本的方法&#xff1a; 本地电脑资源不足&#xff0c;在不增加额外的硬件成本投入的情况下&#xff0c;想要快速提升渲染速度&#xff0c;可使用渲云云渲染&#xff0c;且可批量渲染&#xff0c;批量出结果&#xff0…

centos7密码忘记恢复方法

首先启动系统看到如下界面&#xff1a; 然后按"e"键&#xff0c;看到下面的界面 然后使用"↓"按键移动光标&#xff0c; 移动到linux16 将上图中红色箭头指向的ro替换成下图中画红线的内容&#xff1a; ro替换成rw init/sysroot/bin/sh。 然后按CTRLX进入…

【ABAP】数据类型(五)「结构体概要」

💂作者简介: THUNDER王,一名热爱财税和SAP ABAP编程以及热爱分享的博主。目前于江西师范大学本科在读,同时任汉硕云(广东)科技有限公司ABAP开发顾问。在学习工作中,我通常使用偏后端的开发语言ABAP,SQL进行任务的完成,对SAP企业管理系统,SAP ABAP开发和数据库具有较…

Spring Cloud | No URLs will be polled as dynamic configuration sources.

添加config.properties文件就行了&#xff0c;内容为空的都可以 加上该文件再次运行

基于STM32设计的简易手机

一、项目介绍 基于STM32设计的简易手机可以作为智能手表的模型进行开发&#xff0c;方便老人和儿童佩戴。项目主要是为了解决老年人或儿童使用智能手表时可能遇到的困难&#xff0c;例如操作困难、功能复杂等问题。 在这个项目中&#xff0c;采用了STM32F103RCT6主控芯片和SI…

Effective Java(第三版)目录

本书的目标是帮助读者更加有效地使用Java编程语言及其基本类库java.lang、java.util和java.io&#xff0c;以及子包java.util.concurrent和java.util.function等。本书也会时不时地讨论到其他的类库。 本书一共包含90个条目&#xff0c;每个条目讨论一条规则。这些规则…

驱动 day8 作业

1.在内核模块中启用定时器&#xff0c;定时1s,让led1 一秒亮、一秒灭 2.基于gpio子系统完成LED灯驱动的注册&#xff0c;应用程序测试 1.mychrdev_timer.c #include <linux/init.h> #include <linux/module.h> #include <linux/fs.h> #include <linux/io…

Qt DAY5 Qt制作简易网络聊天室

服务器 widget.h文件 #ifndef WIDGET_H #define WIDGET_H#include <QWidget> #include <QTcpServer> #include <QTcpSocket> #include <QVector>//向量&#xff0c;函数类模板 #include <QMessageBox>namespace Ui { class Widget; }class Wid…

STM32+FreeRTOS 使用SystemView监控系统

前言 本文以STM32F407ZET6 FreeRTOS V9.0作为演示&#xff0c;其它的Cortex M芯片同样可以参考此文&#xff0c;其他内核和RTOS理论上也支持&#xff0c;本文暂时不做研究。 所以开始阅读本文前&#xff0c;需要一块能运行FreeRTOS的Cortex M芯片&#xff0c;如果没有移植好…

发一下接口自动化测试框架(python3+requests+excel)

Git&#xff1a; https://github.com/lilinyu861/Interface-Test 环境配置&#xff1a; 开发工具&#xff1a;pycharm2018Excel 开发框架&#xff1a;python3requestsexcel 接口自动化测试框架介绍&#xff1a; 此接口测试框架&#xff0c;首先由用户设计原始的测试用例并为…

webpack笔记二

文章目录 背景拆分环境清除上次构建产物插件&#xff1a;clean-webpack-plugin合并配置文件插件&#xff1a;webpack-merge实时更新和预览效果&#xff1a;webpack-dev-server babel配置参考 背景 webpack笔记一 在前面的学习&#xff0c;完成了webpack的基本配置&#xff0c…

C++教程——const修饰指针、结构体、文件操作

const修饰指针 常量指针 指针常量 const既修饰指针&#xff0c;又修饰常量 指针与数组 结构体 通过指针访问结构体变量中的数据 结构体中const使用场景 文件操作 写文件 读文件 读取数据的方式 二进制读写文件 写文件 读文件

master、origin master和origin/master

天行健&#xff0c;君子以自强不息&#xff1b;地势坤&#xff0c;君子以厚德载物。 每个人都有惰性&#xff0c;但不断学习是好好生活的根本&#xff0c;共勉&#xff01; 文章均为学习整理笔记&#xff0c;分享记录为主&#xff0c;如有错误请指正&#xff0c;共同学习进步。…

线程任务分支合并框架

1、原理 2、实用类 &#xff08;1&#xff09; ForkJoinPool 分支合并池 类比> 线程池 &#xff08;2&#xff09; ForkJoinTask ForkJoinTask 类比> FutureTask &#xff08;3&#xff09; RecursiveTask 递归任务&#xff1a;继承后可以实现递归(自己调自己)调用…

从小白到大神之路之学习运维第57天--------shell脚本实例应用3.0--以及————结合“三贱客”之“grep”的相关用法

第三阶段基础 时 间&#xff1a;2023年7月11日 参加人&#xff1a;全班人员 内 容&#xff1a; shell实例 目录 一、循环的基本使用 while随机循环 二、case控制服务的基本应用 1、case的语法格式 2、使用case写脚本&#xff0c;以以下实验为主 例1&#xff1a;控…

vue + Luckysheet 实现在线Excel表格操作

需求千千万&#xff0c;又是难熬的一天&#xff01; 效果图&#xff1a; Luckysheet官网网站&#xff1a;快速上手 | Luckysheet文档 1、引入&#xff08;两种&#xff09; 第一种CDN引入 在项目中的 public ---> index.html 中添加代码&#xff0c;如下&#xff1a; &…

91.qt qml-圆角毛玻璃 高斯模糊

qml中使用毛玻璃,可以通过两个类型GaussianBlur或者FastBlur使用,效果如下所示: 接下来先来介绍FastBlur和GaussianBlur 1.FastBlur介绍 FastBlur提供比GaussianBlur更低的模糊质量,但渲染速度更快。FastBlur效果通过使用源内容缩小和双线性滤波的算法模糊源内容来软化源内…

【免费送书活动第一期】赠送实体图书《深入浅出Java虚拟机》JVM原理与实战

赠送实体图书四本&#xff08;免费赠送&#xff09; 《深入浅出JAVA虚拟机&#xff1a;JVM原理与实战》 内容简介&#xff1a; 本书主要以 Java 虚拟机的基本特性及运行原理为中心&#xff0c;深入浅出地分析 JVM 的组成结构和底层实现&#xff0c;介绍了很多性能调优的方案和…

idea编译时遇到的bug

1、 D:\workspace\spark\src\main\Scala\WordCount.scala:3:8 WordCount is already defined as object WordCount object WordCount { 解决参考博客&#xff1a;Error:(21, 8) FlumePushWordCount is already defined as object FlumePushWordCount object FlumePushWor_WSQ(…