【Shiro】Shiro 的学习教程(一)之快速入门

2024-09-08 11:04

本文主要是介绍【Shiro】Shiro 的学习教程(一)之快速入门,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

目录

  • 1、Shiro 简介
  • 2、Shiro 认证、授权
    • 2.1、认证
    • 2.2、授权
  • 3、快速入门
  • 4、自定义 Realm
  • 5、加密
  • 6、实现授权

1、Shiro 简介

Shiro 官网:https://shiro.apache.org/

Shiro 是一个功能强大且易于使用的 Java 安全框架,它执行身份验证、授权、加密和会话管理。使用 Shiro 易于理解的 API,您可以快速轻松地保护任何应用程序—从最小的移动应用程序到最大的 web 和企业应用程序

Shiro 的架构图如下:

在这里插入图片描述
各组件说明如下:

  • Subject:即主体,外部应用与 Subject 进行交互,Subject 记录了当前的操作用户,将用户的概念理解为当前操作的主体。外部程序通过 Subject 进行认证授权,而 Subject 是通过SecurityManager 安全管理器进行认证授权
  • SecurityManager:即安全管理器,对全部的 Subject 进行安全管理,它是 Shiro 的核心,负责对所有的 Subject 进行安全管理。通过 SecurityManager 可以完成 Subject的认证、授权等,实质上SecurityManager 是通过 Authenticator 进行认证,通过 Authorizer 进行授权,通过 SessionManager 进行会话管理等(SecurityManager 是一个接口,继承了 AuthenticatorAuthorizerSessionManager 这三个接口)
  • Authenticator:即认证器,对用户身份进行认证,Authenticator 是一个接口,Shiro 提供 ModularRealmAuthenticator 实现类,通过 ModularRealmAuthenticator 基本上可以满足大多数需求;也可以自定义认证器
  • Authorizer:即授权器,用户通过认证器认证通过,在访问功能时需要通过授权器判断用户是否有此功能的操作权限
  • Realm:即领域,相当于 Datasource 数据源,SecurityManager 进行安全认证,需要通过 Realm 获取用户权限数据,比如:如果用户身份数据在数据库,那么 Realm 就需要从数据库获取用户身份信息。LDAP 数据源的 JndiLdapRealm,JDBC数 据源的 JdbcRealm,ini 文件数据源的 iniRealm,Properties 文件数据源的 PropertiesRealm,等等,我们也可以插入自己的 Realm 实现来代表自定义的数据源
  • SessionManager:即会话管理,Shiro 框架定义了一套会话管理,它不依赖 web 容器的 session,所以 Shiro 可以使用在非 web 应用上,也可以将分布式应用的会话集中在一点管理,此特性可使它实现单点登录
  • SessionDAO:即会话 dao,是对 session 会话操作的一套接口,比如要将 session 存储到数据库,可以通过 jdbc 将会话存储到数据库
  • CacheManager:即缓存管理,将用户权限数据存储在缓存,这样可以提高性能
  • Cryptography:即密码管理,Shiro 提供了一套加密/解密的组件,方便开发。比如提供常用的散列、加/解密等功能

2、Shiro 认证、授权

2.1、认证

身份认证:就是判断一个用户是否为合法用户的处理过程。最常用的简单身份认证方式是系统通过核对用户输入的用户名和口令,看其是否与系统中存储的该用户的用户名和口令一致,来判断用户身份是否正确

在认证过程中,涉及三个概念:

  • Subject:主体。主体可以是用户、程序等,进行认证的都称为主体
  • Principal:身份信息,是主体(Subject)进行身份认证的标识,标识必须具有唯一性。如:用户名、手机号、邮箱地址等,一个主体可以有多个身份,但是必须有一个主身份(Primary Principal)
  • Credential:凭证信息。只有主体自己知道的安全信息,如密码、证书等

2.2、授权

授权方式:

  1. 基于角色
  2. 基于资源

权限字符串

权限字符串的规则是:资源标识符:操作:资源实例标识符,意思是:对哪个资源的哪个实例具有什么操作,“:”是资源/操作/实例的分割符,权限字符串也可以使用 * 通配符

如:

  • 用户创建权限:user:create,或user:create:*
  • 用户修改实例 001 的权限:user:update:001
  • 用户实例 001 的所有权限:user:*:001

3、快速入门

引入 POM 依赖:

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

shiro.ini:位于 resources 资源目录下

# 约定写法
[users]
# 用户名=密码(,角色)
christy=123456,admin
zzc=666666,super
tide=654321,guest[roles]
super=*
admin=guest:*
guest=user:delete:zhangsan

测试类:

public class ShiroAuthenticatorTest2 {public static void main(String[] args) {//准备阶段//// 1.创建安全管理器对象DefaultSecurityManager securityManager = new DefaultSecurityManager();// 2.给安全管理器设置 RealmsecurityManager.setRealm(new IniRealm("classpath:shiro.ini"));// 3.给全局安全工具类 SecurityUtils 设置安全管理器SecurityUtils.setSecurityManager(securityManager);// 4.拿到当前的 SubjectSubject subject = SecurityUtils.getSubject();// 5.创建令牌AuthenticationToken token = new UsernamePasswordToken("christy","123456");try {//认证阶段//// 6.用户认证System.out.println("认证状态:" + subject.isAuthenticated());subject.login(token);System.out.println("认证状态:" + subject.isAuthenticated());} catch (UnknownAccountException e){e.printStackTrace();System.out.println("认证失败:用户不存在!");} catch (IncorrectCredentialsException e){e.printStackTrace();System.out.println("认证失败:密码不正确!");} catch (Exception e){e.printStackTrace();}//授权//// 7.角色授权System.out.println(subject.hasRole("admin"));// 8.资源授权System.out.println(subject.isPermitted("guest:update:01"));}
}

4、自定义 Realm

查看源代码知:有两个抽象方法:

  • 认证AuthenticatingRealm#doGetAuthenticationInfo(AuthenticationToken)
  • 授权AuthorizingRealm#doGetAuthorizationInfo(PrincipalCollection)

且:AuthorizingRealm 继承于 AuthenticatingRealm。意味着自定义的 Reaml 只要继承 AuthorizingRealm,便可重写认证、授权方法

自定义 Reaml:

public class CustomerRealm extends AuthorizingRealm {// 授权@Overrideprotected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {return null;}// 认证@Overrideprotected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {// 在token中获取用户名String principal = (String) authenticationToken.getPrincipal();System.out.println(principal);// 模拟根据身份信息从数据库查询if("christy".equals(principal)){// 参数说明:用户名 | 密码 | 当前realm的名字return new SimpleAuthenticationInfo(principal,"123456", this.getName());}return null;}}

测试:

DefaultSecurityManager securityManager = new DefaultSecurityManager();
securityManager.setRealm(new CustomerRealm());

5、加密

Shiro 中提供了一整套的加密算法,并且提供了随机盐。Shiro 使用指定的加密算法将用户密码和随机盐进行加密,并按照指定的散列次数将散列后的密码存储在数据库中。由于随机盐每个用户可以不同,这就极大的提高了密码的安全性

Md5Hash:有三个构造方法:

  1. public Md5Hash(Object source):只加密
  2. public Md5Hash(Object source, Object salt):加密、加盐
  3. public Md5Hash(Object source, Object salt, int hashIterations):加密、加盐、加散列次数

加密后的 Realm:

public class CustomerRealm extends AuthorizingRealm {@Overrideprotected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {return null;}@Overrideprotected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {// 在token中获取用户名String principal = (String) authenticationToken.getPrincipal();System.out.println(principal);// 模拟根据身份信息从数据库查询if("christy".equals(principal)){// 参数说明:用户名 | 密码(加密后的密码) | 盐 | 当前realm的名字return new SimpleAuthenticationInfo(principal,"41a4e25bcf1272844e38b19047dd68a0", ByteSource.Util.bytes("1q2w3e"), this.getName());}return null;}}

加密后的密码如下:

Md5Hash md5Hash03 = new Md5Hash("123456","1q2w3e", 1024);
// 41a4e25bcf1272844e38b19047dd68a0
System.out.println(md5Hash03.toHex());

测试:

public class ShiroAuthenticatorTest {public static void main(String[] args) {// 1.创建安全管理器对象DefaultSecurityManager securityManager = new DefaultSecurityManager();// 2.给安全管理器设置 Realm//securityManager.setRealm(new IniRealm("classpath:shiro.ini"));CustomerRealm customerRealm = new CustomerRealm();// 3.为 Realm 设置凭证匹配器HashedCredentialsMatcher credentialsMatcher = new HashedCredentialsMatcher();// 设置加密算法credentialsMatcher.setHashAlgorithmName("md5");// 设置hash次数credentialsMatcher.setHashIterations(1024);customerRealm.setCredentialsMatcher(credentialsMatcher);securityManager.setRealm(customerRealm);// 4.给全局安全工具类 SecurityUtils 设置安全管理器SecurityUtils.setSecurityManager(securityManager);// ...  }
}

【注意】:此代码中给 Reaml 设置了 CredentialsMatcher(HashedCredentialsMatcher),代码默认使用 SimpleCredentialsMatcher

CredentialsMatcher 结构图如下:

在这里插入图片描述

6、实现授权

CustomerRealm2

public class CustomerRealm2 extends AuthorizingRealm {// 授权@Overrideprotected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principalCollection) {// 从系统返回的身份信息集合中获取主身份信息(用户名)String primaryPrincipal = (String)principalCollection.getPrimaryPrincipal();System.out.println("用户名: "+primaryPrincipal);// TODO 根据用户名获取当前用户的角色信息,以及权限信息SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();//将数据库中查询角色信息赋值给权限对象simpleAuthorizationInfo.addRole("admin");simpleAuthorizationInfo.addRole("user");//将数据库中查询权限信息赋值个权限对象simpleAuthorizationInfo.addStringPermission("user:*:01");simpleAuthorizationInfo.addStringPermission("product:create");return simpleAuthorizationInfo;}@Overrideprotected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken authenticationToken) throws AuthenticationException {// 在token中获取用户名String principal = (String) authenticationToken.getPrincipal();System.out.println(principal);// 模拟根据身份信息从数据库查询if("christy".equals(principal)){// 参数说明:用户名 | 密码 | 当前realm的名字return new SimpleAuthenticationInfo(principal,"123456", this.getName());}return null;}}

ShiroAuthenticatorTest3

public class ShiroAuthenticatorTest3 {public static void main(String[] args) {// 1.创建安全管理器对象DefaultSecurityManager securityManager = new DefaultSecurityManager();// 2.给安全管理器设置 RealmCustomerRealm2 customerRealm = new CustomerRealm2();securityManager.setRealm(customerRealm);// 3.给全局安全工具类 SecurityUtils 设置安全管理器SecurityUtils.setSecurityManager(securityManager);// 4.拿到当前的 SubjectSubject subject = SecurityUtils.getSubject();// 5.创建令牌AuthenticationToken token = new UsernamePasswordToken("christy","123456");try {// 6、用户认证System.out.println("认证状态:" + subject.isAuthenticated());subject.login(token);System.out.println("认证状态:" + subject.isAuthenticated());} catch (UnknownAccountException e){e.printStackTrace();System.out.println("认证失败:用户不存在!");} catch (IncorrectCredentialsException e){e.printStackTrace();System.out.println("认证失败:密码不正确!");} catch (Exception e){e.printStackTrace();}if (subject.isAuthenticated()) {// 基于角色权限控制System.out.println(subject.hasRole("admin"));//基于多角色权限控制(同时具有)System.out.println(subject.hasAllRoles(Arrays.asList("admin", "super")));//是否具有其中一个角色boolean[] booleans = subject.hasRoles(Arrays.asList("admin", "super", "user"));for (boolean aBoolean : booleans) {System.out.println(aBoolean);}System.out.println("==============================================");System.out.println("权限:"+subject.isPermitted("user:update:01"));System.out.println("权限:"+subject.isPermitted("product:create:02"));//分别具有那些权限boolean[] permitted = subject.isPermitted("user:*:01", "order:*:10");for (boolean b : permitted) {System.out.println(b);}//同时具有哪些权限boolean permittedAll = subject.isPermittedAll("user:*:01", "product:create:01");System.out.println(permittedAll);}}
}

这篇关于【Shiro】Shiro 的学习教程(一)之快速入门的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1147932

相关文章

Python pandas库自学超详细教程

《Pythonpandas库自学超详细教程》文章介绍了Pandas库的基本功能、安装方法及核心操作,涵盖数据导入(CSV/Excel等)、数据结构(Series、DataFrame)、数据清洗、转换... 目录一、什么是Pandas库(1)、Pandas 应用(2)、Pandas 功能(3)、数据结构二、安

Spring WebClient从入门到精通

《SpringWebClient从入门到精通》本文详解SpringWebClient非阻塞响应式特性及优势,涵盖核心API、实战应用与性能优化,对比RestTemplate,为微服务通信提供高效解决... 目录一、WebClient 概述1.1 为什么选择 WebClient?1.2 WebClient 与

2025版mysql8.0.41 winx64 手动安装详细教程

《2025版mysql8.0.41winx64手动安装详细教程》本文指导Windows系统下MySQL安装配置,包含解压、设置环境变量、my.ini配置、初始化密码获取、服务安装与手动启动等步骤,... 目录一、下载安装包二、配置环境变量三、安装配置四、启动 mysql 服务,修改密码一、下载安装包安装地

电脑提示d3dx11_43.dll缺失怎么办? DLL文件丢失的多种修复教程

《电脑提示d3dx11_43.dll缺失怎么办?DLL文件丢失的多种修复教程》在使用电脑玩游戏或运行某些图形处理软件时,有时会遇到系统提示“d3dx11_43.dll缺失”的错误,下面我们就来分享超... 在计算机使用过程中,我们可能会遇到一些错误提示,其中之一就是缺失某个dll文件。其中,d3dx11_4

Linux下在线安装启动VNC教程

《Linux下在线安装启动VNC教程》本文指导在CentOS7上在线安装VNC,包含安装、配置密码、启动/停止、清理重启步骤及注意事项,强调需安装VNC桌面以避免黑屏,并解决端口冲突和目录权限问题... 目录描述安装VNC安装 VNC 桌面可能遇到的问题总结描js述linux中的VNC就类似于Window

Go语言编译环境设置教程

《Go语言编译环境设置教程》Go语言支持高并发(goroutine)、自动垃圾回收,编译为跨平台二进制文件,云原生兼容且社区活跃,开发便捷,内置测试与vet工具辅助检测错误,依赖模块化管理,提升开发效... 目录Go语言优势下载 Go  配置编译环境配置 GOPROXYIDE 设置(VS Code)一些基本

Spring Boot 与微服务入门实战详细总结

《SpringBoot与微服务入门实战详细总结》本文讲解SpringBoot框架的核心特性如快速构建、自动配置、零XML与微服务架构的定义、演进及优缺点,涵盖开发环境准备和HelloWorld实战... 目录一、Spring Boot 核心概述二、微服务架构详解1. 微服务的定义与演进2. 微服务的优缺点三

从入门到精通详解LangChain加载HTML内容的全攻略

《从入门到精通详解LangChain加载HTML内容的全攻略》这篇文章主要为大家详细介绍了如何用LangChain优雅地处理HTML内容,文中的示例代码讲解详细,感兴趣的小伙伴可以跟随小编一起学习一下... 目录引言:当大语言模型遇见html一、HTML加载器为什么需要专门的HTML加载器核心加载器对比表二

从入门到进阶讲解Python自动化Playwright实战指南

《从入门到进阶讲解Python自动化Playwright实战指南》Playwright是针对Python语言的纯自动化工具,它可以通过单个API自动执行Chromium,Firefox和WebKit... 目录Playwright 简介核心优势安装步骤观点与案例结合Playwright 核心功能从零开始学习

Windows环境下解决Matplotlib中文字体显示问题的详细教程

《Windows环境下解决Matplotlib中文字体显示问题的详细教程》本文详细介绍了在Windows下解决Matplotlib中文显示问题的方法,包括安装字体、更新缓存、配置文件设置及编码調整,并... 目录引言问题分析解决方案详解1. 检查系统已安装字体2. 手动添加中文字体(以SimHei为例)步骤