Shiro 自定义realm授权与认证的实现

2024-08-21 15:32

本文主要是介绍Shiro 自定义realm授权与认证的实现,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

……List……

1.项目需求

2.shiro核心组件

3.自定义realm认证

4.自定义realm授权

5.思考总结


……1.项目需求……


          企业项目中少不了权限管理,总的来说,权限管理就是用户认证与用户授权。用户拥有了权限即可操作权限范围内的资源,系统不知道主体是否具有访问权限需要对用户的访问进行控制。shiro是一套优秀的权限管理框架。来了解一下shiro的授权和认证。




……2.shiro核心组件……




关于shiro权限管理(授权和认证)离不开上面三个核心组件:subject,securitymanager,realm。


Subject:即“当前操作用户”,在Shiro中主体,可以是用户也可以是程序,主体要访问系统,系统需要对主体进行认证、授权。

Subject代表了当前用户的安全操作,SecurityManager则管理所有用户的安全操作。 

SecurityManager:它是Shiro框架的核心,典型的Facade模式,Shiro通过SecurityManager来管理内部组件实例,并通过它来提供安全管理的各种服务。 

Realm:域,领域,相当于数据源,通过realm存取认证、授权相关数据。在realm中存储授权和认证的逻辑。所以realm很重要。从这个意义上讲,Realm实质上是一个安全相关的DAO:它封装了数据源的连接细节,并在需要时将相关数据提供给Shiro。当配置Shiro时,你必须至少指定一个Realm,用于认证和(或)授权。配置多个Realm是可以的,但是至少需要一个。 


明白了上面三个基本组件,在分析一下实现的流程:


……3.自定义realm认证……




1、通过ini配置文件创建securityManager

2、调用subject.login方法主体提交认证,提交的token

3、securityManager进行认证,securityManager最终由ModularRealmAuthenticator进行认证。

4、ModularRealmAuthenticator调用IniRealm(给realm传入token) 去ini配置文件中查询用户信息

5、IniRealm根据输入的token(UsernamePasswordToken)从 shiro-first.ini查询用户信息,根据账号查询用户信息(账号和密码)
如果查询到用户信息,就给ModularRealmAuthenticator返回用户信息(账号和密码)
如果查询不到,就给ModularRealmAuthenticator返回null

6、ModularRealmAuthenticator接收IniRealm返回Authentication认证信息
  如果返回的认证信息是null,ModularRealmAuthenticator抛出异常(org.apache.shiro.authc.UnknownAccountException)
         如果返回的认证信息不是null(说明inirealm找到了用户),对IniRealm返回用户密码 (在ini文件中存在)和 token中的密码 进行对比,如果不一致抛出异常(org.apache.shiro.authc.IncorrectCredentialsException)


// 自定义realm@Testpublic void testCustomRealm() {// 创建securityManager工厂,通过ini配置文件创建securityManager工厂Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro-realm.ini");// 创建SecurityManagerSecurityManager securityManager = factory.getInstance();// 将securityManager设置当前的运行环境中SecurityUtils.setSecurityManager(securityManager);// 从SecurityUtils里边创建一个subjectSubject subject = SecurityUtils.getSubject();// 在认证提交前准备token(令牌)// 这里的账号和密码 将来是由用户输入进去UsernamePasswordToken token = new UsernamePasswordToken("zhouzhou","123");try {// 执行认证提交subject.login(token);} catch (AuthenticationException e) {e.printStackTrace();}// 是否认证通过boolean isAuthenticated = subject.isAuthenticated();System.out.println("subject.login(token);之后,是否认证通过:" + isAuthenticated);// 退出操作subject.logout();// 是否认证通过isAuthenticated = subject.isAuthenticated();System.out.println("2.subject.logout();之后是否认证通过:" + isAuthenticated);}


shiro-realm.ini:

[main]
#自定义 realm
customRealm=cn.itcast.shiro.realm.CustomRealm
#将realm设置到securitymanager,相当于spring注入 
securityManager.realms=$customRealm


CumtomRealm.java (自定义类)

package cn.itcast.shiro.realm;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.authz.AuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;public class CustomRealm extends AuthorizingRealm {// 设置realm的名称@Overridepublic void setName(String name) {super.setName("customRealm");}// 用于认证@Overrideprotected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {// token是用户输入的// 第一步从token中取出身份信息String userCode = (String) token.getPrincipal();// 第二步:根据用户输入的userCode从数据库查询// ....// 模拟从数据库查询到密码String password = "123";// 如果查询到返回认证信息AuthenticationInfoSimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(userCode, password, this.getName());return simpleAuthenticationInfo;}// 用于授权@Overrideprotected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {// TODO Auto-generated method stubreturn null;}}

console:



          真正运用到项目中,需要将数据库获取的用户身份信息存入token,subject.isAuthenticated()用这个方法来判断是否通过了认证。


……4.自定义realm授权……




授权与认证类似,是在ini文件里面定义一套授权规则,在环境中去加载。


1、 执行subject.isPermitted("user:create")

2、 securityManager通过ModularRealmAuthorizer进行授权

3、 ModularRealmAuthorizer调用realm获取权限信息

4、 ModularRealmAuthorizer再通过permissionResolver解析权限字符串,校验是否匹配

// 自定义realm进行资源授权测试@Testpublic void testAuthorizationCustomRealm() {// 创建SecurityManager工厂Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:shiro-realm.ini");// 创建SecurityManagerSecurityManager securityManager = factory.getInstance();// 将SecurityManager设置到系统运行环境,和spring后将SecurityManager配置spring容器中,一般单例管理SecurityUtils.setSecurityManager(securityManager);// 创建subjectSubject subject = SecurityUtils.getSubject();// 创建token令牌UsernamePasswordToken token = new UsernamePasswordToken("zhouzhou","123");// 执行认证try {subject.login(token);} catch (AuthenticationException e) {// TODO Auto-generated catch blocke.printStackTrace();}System.out.println("认证状态:" + subject.isAuthenticated());
//		认证状态:true// 认证通过后执行授权// 基于资源的授权,调用isPermitted方法会调用CustomRealm从数据库查询正确权限数据// isPermitted传入权限标识符,判断user:create:1是否在CustomRealm查询到权限数据之内boolean isPermitted = subject.isPermitted("user:create:1");System.out.println("单个权限判断" + isPermitted);
//		单个权限判断trueboolean isPermittedAll = subject.isPermittedAll("user:create:1","user:create");System.out.println("多个权限判断" + isPermittedAll);
//		多个权限判断true// 使用check方法进行授权,如果授权不通过会抛出异常subject.checkPermission("items:add:1");}



shiro-realm.ini:

[main]
#自定义 realm
customRealm=cn.itcast.shiro.realm.CustomRealm
#将realm设置到securitymanager,相当于spring注入 
securityManager.realms=$customRealm



自定义:customRealm.java


package cn.itcast.shiro.realm;import java.util.ArrayList;
import java.util.List;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.authz.AuthorizationInfo;
import org.apache.shiro.authz.SimpleAuthorizationInfo;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;public class CustomRealm extends AuthorizingRealm {// 设置realm的名称@Overridepublic void setName(String name) {super.setName("customRealm");}// 用于认证@Overrideprotected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {// token是用户输入的// 第一步从token中取出身份信息String userCode = (String) token.getPrincipal();// 第二步:根据用户输入的userCode从数据库查询// ....// 模拟从数据库查询到密码String password = "123";// 如果查询到返回认证信息AuthenticationInfoSimpleAuthenticationInfo simpleAuthenticationInfo = new SimpleAuthenticationInfo(userCode, password, this.getName());return simpleAuthenticationInfo;}// 用于授权@Overrideprotected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {//从 principals获取主身份信息//将getPrimaryPrincipal方法返回值转为真实身份类型(在上边的doGetAuthenticationInfo认证通过填充到SimpleAuthenticationInfo中身份类型),String userCode =  (String) principals.getPrimaryPrincipal();//根据身份信息获取权限信息//连接数据库...//模拟从数据库获取到数据List<String> permissions = new ArrayList<String>();permissions.add("user:create");//用户的创建permissions.add("items:add");//商品添加权限//....//查到权限数据,返回授权信息(要包括 上边的permissions)SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo();//将上边查询到授权信息填充到simpleAuthorizationInfo对象中simpleAuthorizationInfo.addStringPermissions(permissions);return simpleAuthorizationInfo;}}




console:




……5.思考总结……

      

       Authorization 授权

      Authentication 认证

      (要分清楚这两个单词…)


      权限管理分为粗粒度和细粒度,细粒度在数据级别没有共同语言,需要写到业务逻辑中。粗粒度权限管理比较容易将权限管理的代码抽取出来在系统架构级别统一处理。节省开发时间,提高开发效率。

      多学习,多思考。




这篇关于Shiro 自定义realm授权与认证的实现的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



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

相关文章

Nginx实现高并发的项目实践

《Nginx实现高并发的项目实践》本文主要介绍了Nginx实现高并发的项目实践,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧... 目录使用最新稳定版本的Nginx合理配置工作进程(workers)配置工作进程连接数(worker_co

python中列表list切分的实现

《python中列表list切分的实现》列表是Python中最常用的数据结构之一,经常需要对列表进行切分操作,本文主要介绍了python中列表list切分的实现,文中通过示例代码介绍的非常详细,对大家... 目录一、列表切片的基本用法1.1 基本切片操作1.2 切片的负索引1.3 切片的省略二、列表切分的高

基于Python实现一个PDF特殊字体提取工具

《基于Python实现一个PDF特殊字体提取工具》在PDF文档处理场景中,我们常常需要针对特定格式的文本内容进行提取分析,本文介绍的PDF特殊字体提取器是一款基于Python开发的桌面应用程序感兴趣的... 目录一、应用背景与功能概述二、技术架构与核心组件2.1 技术选型2.2 系统架构三、核心功能实现解析

dubbo3 filter(过滤器)如何自定义过滤器

《dubbo3filter(过滤器)如何自定义过滤器》dubbo3filter(过滤器)类似于javaweb中的filter和springmvc中的intercaptor,用于在请求发送前或到达前进... 目录dubbo3 filter(过滤器)简介dubbo 过滤器运行时机自定义 filter第一种 @A

使用Python实现表格字段智能去重

《使用Python实现表格字段智能去重》在数据分析和处理过程中,数据清洗是一个至关重要的步骤,其中字段去重是一个常见且关键的任务,下面我们看看如何使用Python进行表格字段智能去重吧... 目录一、引言二、数据重复问题的常见场景与影响三、python在数据清洗中的优势四、基于Python的表格字段智能去重

Spring AI集成DeepSeek实现流式输出的操作方法

《SpringAI集成DeepSeek实现流式输出的操作方法》本文介绍了如何在SpringBoot中使用Sse(Server-SentEvents)技术实现流式输出,后端使用SpringMVC中的S... 目录一、后端代码二、前端代码三、运行项目小天有话说题外话参考资料前面一篇文章我们实现了《Spring

Nginx中location实现多条件匹配的方法详解

《Nginx中location实现多条件匹配的方法详解》在Nginx中,location指令用于匹配请求的URI,虽然location本身是基于单一匹配规则的,但可以通过多种方式实现多个条件的匹配逻辑... 目录1. 概述2. 实现多条件匹配的方式2.1 使用多个 location 块2.2 使用正则表达式

使用Apache POI在Java中实现Excel单元格的合并

《使用ApachePOI在Java中实现Excel单元格的合并》在日常工作中,Excel是一个不可或缺的工具,尤其是在处理大量数据时,本文将介绍如何使用ApachePOI库在Java中实现Excel... 目录工具类介绍工具类代码调用示例依赖配置总结在日常工作中,Excel 是一个不可或缺的工http://

SpringBoot实现导出复杂对象到Excel文件

《SpringBoot实现导出复杂对象到Excel文件》这篇文章主要为大家详细介绍了如何使用Hutool和EasyExcel两种方式来实现在SpringBoot项目中导出复杂对象到Excel文件,需要... 在Spring Boot项目中导出复杂对象到Excel文件,可以利用Hutool或EasyExcel

Python如何实现读取csv文件时忽略文件的编码格式

《Python如何实现读取csv文件时忽略文件的编码格式》我们再日常读取csv文件的时候经常会发现csv文件的格式有多种,所以这篇文章为大家介绍了Python如何实现读取csv文件时忽略文件的编码格式... 目录1、背景介绍2、库的安装3、核心代码4、完整代码1、背景介绍我们再日常读取csv文件的时候经常