SpringSecurity(11)——核心组件和认证流程

获取用户信息

// 获取安全上下文对象,就是那个保存在 ThreadLocal 里面的安全上下文对象
// 总是不为null(如果不存在,则创建一个authentication属性为null的empty安全上下文对象)
SecurityContext securityContext = SecurityContextHolder.getContext();

// 获取当前认证了的 principal(当事人),或者 request token (令牌)
// 如果没有认证,会是 null,该例子是认证之后的情况
Authentication authentication = securityContext.getAuthentication()

// 获取当事人信息对象,返回结果是 Object 类型,但实际上可以是应用程序自定义的带有更多应用相关信息的某个类型。
// 很多情况下,该对象是 Spring Security 核心接口 UserDetails 的一个实现类,你可以把 UserDetails 想像
// 成我们数据库中保存的一个用户信息到 SecurityContextHolder 中 Spring Security 需要的用户信息格式的
// 一个适配器。
Object principal = authentication.getPrincipal();
if (principal instanceof UserDetails) {
	String username = ((UserDetails)principal).getUsername();
} else {
	String username = principal.toString();
}

SecurityContextHolder

SecurityContextHolder持有的是安全上下文的信息,当前操作的用户是谁,用户是否已经被认证,他拥有哪些角色权限等,这些都被保存在SecurityContextHolder中。SecurityContextHolder默认使用ThreadLocal策略来存储认证信息,在web环境下,SpringSecurity在用户登录时自动绑定认证信息到当前线程,在用户退出时,自动清除当前线程的认证信息

public class SecurityContextHolder {

	// 三种工作模式的定义,每种工作模式对应一种策略
	public static final String MODE_THREADLOCAL = "MODE_THREADLOCAL";
	public static final String MODE_INHERITABLETHREADLOCAL = "MODE_INHERITABLETHREADLOCAL";
	public static final String MODE_GLOBAL = "MODE_GLOBAL";

	// 类加载时首先尝试从环境属性中获取所指定的工作模式
	public static final String SYSTEM_PROPERTY = "spring.security.strategy";	
	private static String strategyName = System.getProperty(SYSTEM_PROPERTY);
	private static SecurityContextHolderStrategy strategy;

	// 初始化计数器,初始为0,
	// 1. 类加载过程中会被初始化一次,此值变为1
	// 2. 此后每次调用 setStrategyName 会对新的策略对象执行一次初始化,相应的该值会增1
	private static int initializeCount = 0;

	static {
		initialize();
	}

	/**
	 * 清除上下文
	 */
	public static void clearContext() {
		strategy.clearContext();
	}

	/**
	 * 获取上下文
	 */
	public static SecurityContext getContext() {
		return strategy.getContext();
	}

	/**
	 * 获取计数器的值
	 */
	public static int getInitializeCount() {
		return initializeCount;
	}

	private static void initialize() {
		if (!StringUtils.hasText(strategyName)) {
			// Set default, 设置缺省工作模式/策略 MODE_THREADLOCAL
			strategyName = MODE_THREADLOCAL;
		}

		if (strategyName.equals(MODE_THREADLOCAL)) {
			strategy = new ThreadLocalSecurityContextHolderStrategy();
		} else if (strategyName.equals(MODE_INHERITABLETHREADLOCAL)) {
			strategy = new InheritableThreadLocalSecurityContextHolderStrategy();
		} else if (strategyName.equals(MODE_GLOBAL)) {
			strategy = new GlobalSecurityContextHolderStrategy();
		} else {
			// Try to load a custom strategy
			try {
				Class<?> clazz = Class.forName(strategyName);
				Constructor<?> customStrategy = clazz.getConstructor();
				strategy = (SecurityContextHolderStrategy) customStrategy.newInstance();
			}
			catch (Exception ex) {
				ReflectionUtils.handleReflectionException(ex);
			}
		}
		initializeCount++;
	}

	/**
	 * 设置上下文
	 */
	public static void setContext(SecurityContext context) {
		strategy.setContext(context);
	}

	/**
	 * 设置工作模式
	 */
	public static void setStrategyName(String strategyName) {
		SecurityContextHolder.strategyName = strategyName;
		initialize();
	}

	/**
	 * 获取对应工作模式的策略
	 */
	public static SecurityContextHolderStrategy getContextHolderStrategy() {
		return strategy;
	}

	/**
	 * 创建空的上下文信息
	 */
	public static SecurityContext createEmptyContext() {
		return strategy.createEmptyContext();
	}

	public String toString() {
		return "SecurityContextHolder[strategy='" + strategyName + "'; initializeCount="
				+ initializeCount + "]";
	}
}

SecurityContext

安全上下文,主要持有Authentication对象,如果用户未鉴权,那么Authentication对象将会是空的

public interface SecurityContext extends Serializable {
	/**
	 * 获取当前经过身份验证的主体,或身份验证请求令牌
	 */
	Authentication getAuthentication();

	/**
	 * 更改当前经过身份验证的主体,或删除身份验证信息
	 */
	void setAuthentication(Authentication authentication);
}

Authentication

鉴权对象,该对象主要包含了用户的详细信息(UserDetails)和用户鉴权所需要的信息,如用户提交的用户名密码、Remember-me Token或digest hash值等,按不同鉴权方式使用不同的Authentication实现

public interface Authentication extends Principal, Serializable {
    //用来获取用户的权限。
    Collection<? extends GrantedAuthority> getAuthorities();
    //用来获取用户凭证,一般来说就是密码。
    Object getCredentials();
    //用来获取用户携带的详细信息,可能是当前请求之类的东西。
    Object getDetails();
    //用来获取当前用户,可能是一个用户名,也可能是一个用户对象。
    Object getPrincipal();
    //判断当前用户是否认证成功。
    boolean isAuthenticated();
	//设置用户是否认证成功
    void setAuthenticated(boolean var1) throws IllegalArgumentException;
}

GrantedAuthority

表示了当前用户所拥有的权限(或角色)信息,这些信息由授权负责对象AccessDecisionManager来使用,并决定最终用户是否可以访问某资源(URL或方法调用或域对象),鉴权使并不会使用到该对象

public interface GrantedAuthority extends Serializable {
    //获取当前用户所拥有的权限(或角色)信息
    String getAuthority();
}

UserDetailsService

提供一个接口loadUserByUsername(String username),一般通过扩展该接口显式获取我们的用户信息,用户登陆时传递的用户名和密码也是通过这里查找出来的用户名和密码进行校验,真正的校验由AuthenticationManager和AuthenticationProvider负责的。如果用户不存在时应返回NULL,而是抛出异常UsernameNotFoundException

public interface UserDetailsService {
    UserDetails loadUserByUsername(String var1) throws UsernameNotFoundException;
}

UserDetails

规范了用户详细信息所拥有的字段,如用户名、密码、账号是否过期、是否锁定等,在SpringSecurity中,获取当前登录的用户的信息,一般情况是需要在该接口上面进行扩展

public interface UserDetails extends Serializable {
    // 返回权限集合
    Collection<? extends GrantedAuthority> getAuthorities();
    // 获取密码
    String getPassword();
    // 获取用户名
    String getUsername();
    // 判断用户是否未过期
    boolean isAccountNonExpired();
    // 判断账户是否未锁定
    boolean isAccountNonLocked();
    // 判断用户凭证是否没过期,即密码是否未过期
    boolean isCredentialsNonExpired();
    // 判断用户是否可用
    boolean isEnabled();
}

安全身份认证流程

过滤器链

认证流程

在这里插入图片描述

在线绘图工具,ER模型设计-Spring-Security分析,流程图制作工具,设计流程图,visio流程图,在线流程图制作,如何制作流程图 ...

  1. Spring Security定义了一个过滤器链,当认证请求到达这个链时,该请求将会穿过这个链条用于认证和授权,这个链上可以定义1~N个过滤器,过滤器的用途是获取请求中的认证信息,根据认证方法进行路由,把认证信息传递给对应的认证处理程序进行处理,不同的过滤器处理不同的认证信息
  • HTTP Basic认证通过过滤器链,到达BasicAuthenticationFilter
  • HTTP Digest认证被DigestAuthenticationFilter识别,拦截并处理
  • 表单登录认证被UsernamePasswordAuthenticationFilter识别,拦截并处理
  1. 基于用户凭证创建AuthenticationToken

如:用户在登录表单中输入用户名和密码,并点击确定,浏览器提交POST请求到服务器,穿过过滤器链,被UsernamePasswordAuthenticationFilter识别,UsernamePasswordAuthenticationFilter提取请求中的用户名和密码来创建UsernamePasswordAuthenticationToken对象

  1. 把组装好的AuthenticationToken传递给AuthenticationManager

如:组装好的UsernamePasswordAuthenticationToken对象被传递给AuthenticationManager的authenticate方法进行认证决策,AuthenticationManager只是一个接口,实际的实现是ProviderManager

  1. ProviderManager委托给AuthenticationProvider进行认证处理

AuthenticationProvider提供了不同的实现类,ProviderManager会把收到的UsernamePasswordAuthenticationToken对象传递给列表中的每一个AuthenticationProvider进行认证,那UsernamePasswordAuthenticationToken会被哪一个接收和处理呢?是由supports方法来决定的

  1. UserDetailsService获取用户信息

例如:DaoAuthenticationProvider通过UserDetailsService查找对应的用户信息

  1. 认证结果处理

例如:如果认证成功(用户名和密码完全正确),AuthenticationProvider将会返回一个完全有效的Authentication对象(UsernamePasswordAuthenticationToken),否则抛出AuthenticationException异常

认证完成后,AuthenticationManager将会返回该认证对象(UsernamePasswordAuthenticationToken)返回给过滤器

  1. 存储认证对象。相关的过滤器获得一个认证对象后,把他存储在安全上下文中(SecurityContext)用于后续的授权判断

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

JS进阶-作用域、垃圾回收机制、闭包、变量提升(一)

• 作用域 作用域&#xff08;scope&#xff09;规定了变量能够被访问的“范围”&#xff0c;离开了这个“范围”变量便不能被访问 作用域分为&#xff1a; 局部作用域 全局作用域 • 局部作用域 局部作用域分为函数作用域和块作用域。 1. 函数作用域&#xff1a; 在函数内…

Kafka常见指令及监控程序介绍

kafka在流数据、IO削峰上非常有用&#xff0c;以下对于这款程序&#xff0c;做一些常见指令介绍。 下文使用–bootstrap-server 10.0.0.102:9092,10.0.0.103:9092,10.0.0.104:9092 需自行填写各自对应的集群IP和kafka的端口。 该写法 等同 –bootstrap-server localhost:9092 …

RabbitMQ数据隔离

1、新建用户 2、登录用户&#xff0c;设置虚拟主机 登录用户只能操作自己的虚拟主机&#xff0c;交换机等&#xff0c;不能操作其他人的&#xff01;&#xff01;&#xff01;

【立创EDA-PCB设计基础】3.网络表概念解读+板框绘制

前言&#xff1a;本文对网络表概念解读板框绘制&#xff08;确定PCB板子轮廓&#xff09; 网络表概念解读 在本专栏的上一篇文章【嘉立创EDA-PCB设计指南】2&#xff0c;将设计的原理图转为了PCB&#xff0c;在PCB界面下出现了所有的封装&#xff0c;以及所有的飞线属性&…

MSI模块应用:可变N进制计数器设计

将集成组合逻辑电路模块和时序逻辑电路模块结合起来实现某种电路功能&#xff0c;一般多见于译码器、数据选择器和计数器的综合应用&#xff0c;以实现节拍信号发生器或序列信号发生器。本文介绍另一种题型&#xff0c;即数值比较器和计数器的综合应用。&#xff08;典型试题&a…

最全笔记软件盘点!你要的笔记神器都在这里:手写笔记、知识管理、文本笔记、协作笔记等!

在当今的信息化社会中&#xff0c;人们对信息的处理速度越来越快&#xff0c;从工作到生活&#xff0c;我们都面临着大量信息的冲击。在这样的环境下&#xff0c;一个能够帮助我们管理、整理和储存信息的好工具显得尤为重要&#xff0c;而笔记软件恰恰可以满足这些需求。 在选…

在IDEA中使用快捷键让XML注释更加规范

Setting -> Editor -> Code Style -> XML 取消勾选 Line comment at first column 这样我们在使用ctrl / 快速注释时&#xff0c;就可以让注释符号紧贴注释内容&#xff0c;不出现空格。

vue+elementUI el-select 中 没有加clearable出现一个或者多个×清除图标问题

1、现象&#xff1a;下方截图多清除图标了 2、在全局common.scss文件中加一个下方的全局样式noClear 3、在多清除图标的组件上层div加noClear样式 4、清除图标去除成功

【C++进阶07】哈希表and哈希桶

一、哈希概念 顺序结构以及平衡树中 元素关键码与存储位置没有对应关系 因此查找一个元素 必须经过关键码的多次比较 顺序查找时间复杂度为O(N) 平衡树中为树的高度&#xff0c;即O( l o g 2 N log_2 N log2​N) 搜索效率 搜索过程中元素的比较次数 理想的搜索方法&#xff1a…

知识库是什么:中小型企业都要知道的重要讯息

在当今信息爆炸的年代&#xff0c;久而久之&#xff0c;企业可能发现自己沉浸在各种信息、学习资料和数据中。这就使得组织和管理这些信息变得尤为重要。进入我们的视线的就是“知识库”&#xff0c;它其实就像一个企业自己的“小图书馆”&#xff0c;只不过&#xff0c;这个库…

如何提取3D动画中的模型---模大狮模型网

在现代媒体制作和设计领域&#xff0c;3D动画已经成为一种常见的表达方式。如果您对一部3D动画中的某个特定模型非常感兴趣&#xff0c;并且想要提取出来以便进行后续操作或学习&#xff0c;模大狮将向您介绍一些方法和步骤。 一、选择适当的软件 要提取3D动画中的模型&#x…

Vue (v-bind指令、el与data的两种写法、理解MVVM、数据代理、V-no事件处理、双向数据绑定V-model、登陆页面实现

V-bind指令 el与data两种写法 MVVM 数据代理 V-no事件处理 V-no用于监听DOM对象 双向数据绑定V-model v-model 指令用来在 input、select、textarea、checkbox、radio 等表单控件元素上创建双向数据绑定&#xff0c;根据表单上的值&#xff0c;自动更新绑定的元素的值。 按钮的…

【MATLAB】ICEEMDAN+FFT+HHT组合算法

代码基本原理 ICEEMDAN&#xff08;改进的完全经验模态分解与自适应噪声&#xff09;FFT&#xff08;快速傅里叶变换&#xff09;HHT&#xff08;希尔伯特-黄变换&#xff09;组合算法是一种用于信号处理和分析的复杂组合算法。它结合了ICEEMDAN、FFT和HHT三个步骤&#xff0c…

ChatGLM3报错:No chat template is defined for this tokenizer

使用官方提供的脚本创建ChatGLM3的DEMO&#xff1a; cd basic_demo python web_demo_gradio.py 出现效果异常问题&#xff1a; conversation [{role: user, content: 你好}, {role: assistant, content: 你好&#xff0c;有什么我可以帮助你的吗&#xff1f;\n\n<|im_end|…

家用洗地机选什么牌子好?洗地机口碑榜

随着科技的迅猛发展&#xff0c;许多智能家电让我们的生活更加便利和轻松。在这不断迭代更新的产品中&#xff0c;洗地机逐渐取代了传统的扫地机器人和吸尘器&#xff0c;成为一款集多种功能于一身的多功能清洁工具。它不仅继承了扫地机器人的吸尘功能&#xff0c;还能够轻松完…

算法训练营Day45

#Java #动态规划 Feeling and experiences&#xff1a; 最长公共子序列&#xff1a;力扣题目链接 给定两个字符串 text1 和 text2&#xff0c;返回这两个字符串的最长 公共子序列 的长度。如果不存在 公共子序列 &#xff0c;返回 0 。 一个字符串的 子序列 是指这样一个新…

Mybatis-Generator-1.4.2

知道代码自动化原理&#xff0c;可以自己搞的&#xff0c;连客户端js html一起弄掉 Low Code Development Platform(LCDP)_cms lcdp-CSDN博客

ARM-Linux驱动内核(S3C2440)

Linux启动流程 驱动(程序) &#xff1a; 驱使设备行动的程序 1. 启动bootloader---引导操作系统启动的(裸机)程序&#xff0c;为操作系统启动准备环境&#xff0c;并引导操作系统启动 2. 启动kernel---操作系统核心 (俗称的操作系统) 3. 加载根文件系统---一堆文件的集合…

JanusGraph图数据库的应用以及知识图谱技术介绍

目录 JanusGraph介绍 JanusGraph 的主要优势 JanusGraph的应用&#xff1a; JanusGraph 的行业应用&#xff1a; 架构概览 分布式技术应用 横向扩展能力 程序与janus的交互 Janus与图数据库相关概念 结构化存储 图结构存储 实体关系存储 知识存储技术 JanusGraph介…

无人机航迹规划(四):七种元启发算法(DBO、LO、SWO、COA、LSO、KOA、GRO)求解无人机路径规划(提供MATLAB代码)

一、七种算法&#xff08;DBO、LO、SWO、COA、LSO、KOA、GRO&#xff09;简介 1、蜣螂优化算法DBO 蜣螂优化算法&#xff08;Dung beetle optimizer&#xff0c;DBO&#xff09;由Jiankai Xue和Bo Shen于2022年提出&#xff0c;该算法主要受蜣螂的滚球、跳舞、觅食、偷窃和繁殖…