spring-security--基础--02--核心组件

2023-11-01

spring-security–基础–02–核心组件


1、SecurityContextHolder

  1. 最基本的对象
  2. 它负责存储当前安全上下文信息。
    1. 保存着当前用户是什么,是否已经通过认证,拥有哪些权限.
  3. 默认使用ThreadLocal策略来存储认证信息,这是一种与线程绑定的策略。
    1. 在Web场景下的使用Spring Security,在用户登录时自动绑定认证信息到当前线程,在用户退出时,自动清除当前线程的认证信息。

1.1、获取有关当前用户的信息

Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();

2、Authentication

package org.springframework.security.core; 

public interface Authentication extends Principal, Serializable {  
	Collection<? extends GrantedAuthority> getAuthorities();  

	Object getCredentials(); 

	Object getDetails(); 

	Object getPrincipal(); 

	boolean isAuthenticated(); 

	void setAuthenticated(boolean var1)throws IllegalArgumentException;
}
  1. 是Spring Security中最高级别的认证。
  2. getAuthorities:获取权限列表
  3. getCredentials:获取密码信息,由用户输入的密码凭证,认证之后会移出,来保证安全性;
  4. getDetails:细节信息,web应用中的实现接口通常为WebAuthenticationDetails,它记录了访问者的ip地址和sessionId的值。
  5. getPrincipal:获取身份信息,一般返回UserDetails的实现类;

3、UserDetails


public interface UserDetails extends Serializable {

   Collection<? extends GrantedAuthority> getAuthorities();

   String getPassword();

   String getUsername();

   boolean isAccountNonExpired();

   boolean isAccountNonLocked();

   boolean isCredentialsNonExpired();

   boolean isEnabled();
}
  1. 代表了最详细的用户信息
  2. 这个接口涵盖了一些必要的用户信息字段

3.1、和Authentication区别

  1. Authentication中的getCredentials来源于用户提交的密码凭证,而UserDetails中的getPassword取到是用户正确的密码信息。
  2. Authentication中的getAuthorities是认证用户名和密码成功之后,由UserDetails中的getAuthorities传递而来。而Authentication中的getDetails信息是经过了AuthenticationProvider认证之后填充的。

4、UserDetailsService

public interface UserDetailsService {
   UserDetails loadUserByUsername(String username)throws UsernameNotFoundException;
}
  1. loadUserByUsername:就是从特定的地方(一般是从数据库中)加载用户信息。
    1. 常用的实现类
      1. JdbcDaoImpl:从数据库中加载用户
      2. InMemoryUserDetailsManager:从内存中加载用户
    2. 可以自己实现UserDetailsService

5、AuthenticationManager

public interface AuthenticationManager {
	Authentication authenticate(Authentication authentication)throws AuthenticationException;
			
}
  1. authenticate:
    1. 用于认证
    2. 认证相关的核心接口
    3. 发起认证的出发点
    4. Spring推荐通过实现AuthenticationManager接口来自定义自己的认证方式
    5. 默认的实现:ProviderManager
  2. 保留了关键认证部分的 ProviderManager 源码:
public class ProviderManager implements AuthenticationManager, MessageSourceAware,
		InitializingBean {

	// 维护一个 AuthenticationProvider 列表
	private List<AuthenticationProvider> providers = Collections.emptyList();
		  
	public Authentication authenticate(Authentication authentication)
		  throws AuthenticationException {
	   Class<? extends Authentication> toTest = authentication.getClass();
	   AuthenticationException lastException = null;
	   Authentication result = null;

	   // 依次认证
	   for(AuthenticationProvider provider : getProviders()){
		  if(!provider.supports(toTest)){
			 continue;
		  }
		  try {
			 result = provider.authenticate(authentication);

			 if(result != null){
				copyDetails(authentication, result);
				break;
			 }
		  }
		  ...
		  catch(AuthenticationException e){
			 lastException = e;
		  }
	   }
	   // 如果有 Authentication 信息,则直接返回
	   if(result != null){
			if(eraseCredentialsAfterAuthentication
					&&(result instanceof CredentialsContainer)){
				 // 移除密码
			((CredentialsContainer)result).eraseCredentials();
			}
			 // 发布登录成功事件
			eventPublisher.publishAuthenticationSuccess(result);
			return result;
	   }
	   ...
	   // 执行到此,说明没有认证成功,包装异常信息
	   if(lastException == null){
		  lastException = new ProviderNotFoundException(messages.getMessage(
				"ProviderManager.providerNotFound",
				new Object[] { toTest.getName()},
				"No AuthenticationProvider found for {0}"));
	   }
	   prepareException(lastException, authentication);
	   throw lastException;
	}
}

ProviderManager中的List,会依照次序去认证,认证成功则立即返回,若认证失败则返回null,下一个AuthenticationProvider会继续尝试认证,如果所有认证器都无法认证成功,则ProviderManager会抛出一个ProviderNotFoundException异常。

到这里,如果不纠结于AuthenticationProvider的实现细节以及安全相关的过滤器,认证相关的核心类其实都已经介绍完毕了:身份信息的存放容器SecurityContextHolder,身份信息的抽象Authentication,身份认证器AuthenticationManager及其认证流程。姑且在这里做一个分隔线。

6、AuthenticationProvider

public interface AuthenticationProvider {
	
	Authentication authenticate(Authentication authentication)
			throws AuthenticationException;

	
	boolean supports(Class<?> authentication);
}
  1. authenticate():认证方法
    1. 定义了认证的实现过程,它的参数Authentication里面包含了登录用户所提交的用户、密码等。返回值也是一个Authentication,这个Authentication则是在认证成功后,将用户的权限及其他信息重新组装后生成。
  2. SpringSecurity中维护着一个List列表,存放多种认证方式,不同的认证方式使用不同的AuthenticationProvider。如使用用户名密码登录时,使用AuthenticationProvider1,短信登录时使用AuthenticationProvider2等等这样的例子很多。
  3. supports():满足什么样的身份信息才进行如上认证
    1. 每个AuthenticationProvider需要实现supports()方法来表明自己支持的认证方式,如我们使用表单方式认证,在提交请求时SpringSecurity会生成UsernamePasswordAuthenticationToken,它是一个Authentication,里面封装着用户提交的用户名、密码信息。
  4. 可以自己实现AuthenticationProvider接口来自定义认证

6.1、实现类

  1. DaoAuthenticationProvider:从数据库中读取用户信息验证身份
  2. AnonymousAuthenticationProvider:匿名用户身份认证
  3. RememberMeAuthenticationProvider:已存cookie中的用户信息身份认证
  4. AuthByAdapterProvider:使用容器的适配器验证身份
  5. CasAuthenticationProvider:根据Yale中心认证服务验证身份,用于实现单点登陆
  6. JaasAuthenticationProvider:从JASS登陆配置中获取用户信息验证身份
  7. RemoteAuthenticationProvider:根据远程服务验证用户身份
  8. RunAsImplAuthenticationProvider:对身份已被管理器替换的用户进行验证
  9. X509AuthenticationProvider:从X509认证中获取用户信息验证身份
  10. TestingAuthenticationProvider:单元测试时使用

6.2、DaoAuthenticationProvider源码

public class DaoAuthenticationProvider extends AbstractUserDetailsAuthenticationProvider {
	//密码加解密算法
	private PasswordEncoder passwordEncoder;
	//用户信息dao
	private UserDetailsService userDetailsService;
	
	//检查用户名和密码是否匹配
	protected void additionalAuthenticationChecks(UserDetails userDetails,
			UsernamePasswordAuthenticationToken authentication)
			throws AuthenticationException {
		if(authentication.getCredentials()== null){
			throw new BadCredentialsException(messages.getMessage(
					"AbstractUserDetailsAuthenticationProvider.badCredentials",
					"Bad credentials"));
		}
		//用户提交的密码凭证
		String presentedPassword = authentication.getCredentials().toString();
		//比较两个密码
		if(!passwordEncoder.matches(presentedPassword, userDetails.getPassword())){
				throw new BadCredentialsException(messages.getMessage(
					"AbstractUserDetailsAuthenticationProvider.badCredentials",
					"Bad credentials"));
		}
	}


	//获取用户信息
	protected final UserDetails retrieveUser(String username,
			UsernamePasswordAuthenticationToken authentication)
			throws AuthenticationException {
			UserDetails loadedUser = this.getUserDetailsService().loadUserByUsername(username);
	}
}

7、SecurityContext

public interface SecurityContext extends Serializable {
	Authentication getAuthentication();

	void setAuthentication(Authentication var1);
}
  1. 安全上下文
  2. getAuthentication():获取上下文

8、总结

8.1、uml图

在这里插入图片描述

8.2、整个认证过程

在这里插入图片描述

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

spring-security--基础--02--核心组件 的相关文章

随机推荐

  • CentOS7.4 离线升级openssh8.4

    CentOS7 4 离线升级openssh8 4 前言 工作中需要离线升级openssh 网上一些资料说要先安装telnet 这里省略 大家可以先安装telnet 预防更新ssh失败 下载openssl安装包 去https www open
  • 数据分析——时间序列分析模型(AR,MA,ARMA,ARIMA)

    1 概述 时间序列是某个时间段或者某些时间点对应的不同数值的数值对 这些数值对只有两个具体数据 时间要素 数值要素 时间要素可以是某一个时间段或者某一个时刻 例如一个杂货铺一周 七天 的销售额为时间段的时间要素 而一天二十四小时每个整点所对
  • Spring之Bean生命周期源码解析-Bean销毁

    这篇文章是我在系统学习Spring源码之后 基于自己对Spring源码的理解 来详细分析Spring之Bean的销毁过程 目录 前言 一 注册有销毁逻辑的Bean 1 判断当前Bean是否需要销毁 1 1 判断当前Bean是否有销毁方法 1
  • 华为OD机试 - 统计射击比赛成绩(Java)

    题目描述 给定一个射击比赛成绩单 包含多个选手若干次射击的成绩分数 请对每个选手按其最高3个分数之和进行降序排名 输出降序排名后的选手ID序列 条件如下 一个选手可以有多个射击成绩的分数 且次序不固定 如果一个选手成绩少于3个 则认为选手的
  • 03-NodeMCU引脚和接线、点亮外部LED

    Author teacherXue 一 ESP8266 引脚参考 ESP8266 12 E 芯片带有 17 个 GPIO 引脚 并不是所有的ESP8266开发板都开放了所有的GPIO 并且由于电力设计原因 以及有些GPIO有非常特殊的功能
  • malloc函数详解

    一 原型 extern void malloc unsigned int num bytes 头文件 include
  • Pixi的基本使用(5)--寻宝猎人

    寻宝猎人 游戏需求 使用键盘上的箭头键帮助探险家找到宝藏并将其带到出口 怪物在地牢壁之间上下移动 如果探险家触碰到怪物则变成半透明 并且右上角的生命值会减少 如果所有生命值都用光了 会显示 You Lost 如果探险家带着宝藏到达出口 会显
  • QT TCP简单的通信示例

    TCP服务端 第一步 创建监听套接字的QTcpSever QTcpServer m tsTcpServer 第二部步 listen 监听是否有新的连接进来 int iMyport 如果有新的客户端连接的话 会触发信号newConnectio
  • Lyapunov

    一 正定函数 令是向量x的标量函数 S是x空间包含原点的封闭有限区域 如果对于S中所有的x 都有 1 存在且连续 2 3 当时 则V x 是正定的 半正定 的 二 二次型 1 定义 在李雅普诺夫第二方法上的稳定性分析中 二次型函数起着重要作
  • 课时 16 深入理解 etcd:基于原理解析(曾凡松)

    本文将主要分享以下三方面的内容 第一部分 会为大家介绍 etcd 项目发展的整个历程 从诞生至今 etcd 经历的那些重要的时刻 第二部分 会为大家介绍 etcd 的技术架构以及其内部的实现机制 通过对技术架构和内部机制的学习 帮助我们正确
  • 如何在JCreator中导入.jar文件

    本文摘自http www lvchao org 上篇介绍了如何在Eclipse中导入 jar包 这篇将介绍在JCreator中导入 jar包 与上篇一样 先建立一个Project 请注意 建立工程的目的是方便管理和使用 建议那些不喜欢这样做
  • 电脑宏基电脑,【宏基电脑】报价_介绍_图片_评论_咨询-宏基电脑产品大全 -真快乐商城...

    宏基电脑怎么重装系统 标签 时间 2013 10 18 10 27 10 很多朋友有这样的疑问 宏基电脑怎么重装系统 的问题 所以国美小编总结了有关宏基电脑装系统的相关知识 现在和大家一起分享 1 使用宏基电脑自带的系统光盘安装 先要在BI
  • LeetCode 2108. 找出数组中的第一个回文字符串

    给你一个字符串数组 words 找出并返回数组中的 第一个回文字符串 如果不存在满足要求的字符串 返回一个 空字符串 回文字符串 的定义为 如果一个字符串正着读和反着读一样 那么该字符串就是一个 回文字符串 示例 1 输入 words ab
  • multiprocessing.pool详解

    由于python有全局锁限制 如果想利用多核 就需要使用多进程模块 但该模块有很多坑 本篇文章记录一下其用法以及踩过的坑 一 map apply apply async对比 先贴一个对比图 引自multiprocessin pool Mul
  • CmakeList--glog

    file GLOB GLOG LIBRARIES usr lib x86 64 linux gnu libglog so set GLOG INCLUDE DIRS usr include message glog include dirs
  • 安装vb6 正在更新系统 无响应

    新装的win10系统 安装vb6时 最后一直卡在 正在更新系统 程序无响应 没办法 kill掉后 貌似不影响软件使用 但是安装vs6sp6B无法成功安装 解决办法是 不安装 数据访问 组件 参考 http bbs pcbeta com vi
  • 多路采集存储c语言程序,stm32多路巡回数据采集系统设计 含源程序

    此次设计是利用stm32开发板设计的 数据采集系统是模拟域与数字域之间必不可少的纽带 它的存在具有着非常重要的作用 本文介绍的重点是数据采集系统 而该系统硬件部分的重心在于单片机芯片 数据采集与通信控制采用了模块化的设计 数据采集与通信控制
  • qsort的自主实现

    目录 qsort 函数的功能 首先回忆一下冒泡排序是如何实现的 需要改动的地方 compare swap qosrt 函数实现 快速排序实现qsort 已经成功 今天我要分享的是qsort的自主实现 冒泡版qsort 标准是用的快速排序 好
  • Kendo UI开发教程(24): 单页面应用(二) Router 类

    Route类负责跟踪应用的当前状态和支持在应用的不同状态之间切换 Route通过Url的片段功能 url 和流量器的浏览历史功能融合在一起 从而可以支持把应用的某个状态作为书签添加到浏览器中 Route也支持通过代码在应用的不同状态之间切换
  • spring-security--基础--02--核心组件

    spring security 基础 02 核心组件 1 SecurityContextHolder 最基本的对象 它负责存储当前安全上下文信息 保存着当前用户是什么 是否已经通过认证 拥有哪些权限 默认使用ThreadLocal策略来存储