【Spring Boot】Spring 的安全框架:Spring Security

news2024/11/20 15:28:58

Spring 的安全框架:Spring Security

  • 1.Spring Security 初识
    • 1.1 核心概念
    • 1.2 认证和授权
      • 1.2.1 验证(authentication)
      • 1.2.2 授权(authorization)
    • 1.3 模块
  • 2.核心类
    • 2.1 Securitycontext
    • 2.2 SecurityContextHolder
      • 2.2.1 strategy 实现
      • 2.2.2 获取当前用户的 SecurityContext
    • 2.3 ProviderManager
    • 2.4 DaoAuthenticationProvider
    • 2.5 UserDetails
    • 2.6 UserDetailsService
    • 2.7 GrantedAuthority
    • 2.8 Filter

1.Spring Security 初识

Spring Security 提供了声明式的安全访问控制解决方案(仅支持基于 Spring 的应用程序),对访问权限进行认证和授权,它基于 Spring AOP 和 Servlet 过滤器,提供了安全性方面的全面解决方案。

除常规的认证和授权外,它还提供了 ACLs、LDAP、JAAS、CAS 等高级特性以满足复杂环境下的安全需求。

1.1 核心概念

Spring Security 的 3 个核心概念。

  • Principle:代表用户的对象 Principle(User),不仅指人类,还包括一切可以用于验证的设备。
  • Authority:代表用户的角色 Authority(Role),每个用户都应该有一种角色,如管理员或是会员。
  • Permission:代表授权,复杂的应用环境需要对角色的权限进行表述。

在 Spring Security 中,Authority 和 Permission 是两个完全独立的概念,两者并没有必然的联系。它们之间需要通过配置进行关联,可以是自己定义的各种关系。

1.2 认证和授权

安全主要分为 验证authentication)和 授权authorization)两个部分。

1.2.1 验证(authentication)

验证 指的是,建立系统使用者信息(Principal)的过程。使用者可以是一个用户、设备,和可以在应用程序中执行某种操作的其他系统。

用户认证一般要求用户提供用户名和密码,系统通过校验用户名和密码的正确性来完成认证的通过或拒绝过程。

Spring Security 支持主流的认证方式,包括 HTTP 基本认证、 HTTP 表单验证、HTTP 摘要认证、Open ID 和 LDAP 等。

Spring Security 进行验证的步骤如下。

  • 1️⃣ 用户使用用户名和密码登录。
  • 2️⃣ 过滤器(UsemamePasswordAuthenticationFilter)获取到用户名、密码,然后封装成 Authentication。
  • 3️⃣ AuthenticationManager 认证 token (Authentication 的实现类传递)。
  • 4️⃣ AuthenticationManager 认证成功,返回一个封装了用户权限信息的 Authentication 对象, 用户的上下文信息(角色列表等)。
  • 5️⃣ Authentication 对象赋值给当前的 SecurityContext,建立这个用户的安全上下文(通过调用 SecurityContextHolder.getContext().setAuthentication())。
  • 6️⃣ 用户进行一些受到访问控制机制保护的操作,访问控制机制会依据当前安全上下文信息检查这个操作所需的权限。

除利用提供的认证外,还可以编写自己的 Filter(过滤器),提供与那些不是基于 Spring Security 的验证系统的操作。

1.2.2 授权(authorization)

在一个系统中,不同用户具有的权限是不同的。一般来说,系统会为不同的用户分配不同的角色,而每个角色则对应一系列的权限。

它判断某个 Principal 在应用程序中是否允许执行某个操作。在进行授权判断之前,要求其所要使用到的规则必须在验证过程中已经建立好了。

对 Web 资源的保护,最好的办法是使用过滤器。对方法调用的保护,最好的办法是使用 AOP。

Spring Security 在进行用户认证及授予权限时,也是通过各种拦截器和 AOP 来控制权限访问的,从而实现安全。

1.3 模块

名称模块
解释
核心模块spring-security-core.jar包含核心验证和访问控制类和接口,以及支持远程配置的基本 API。
远程调用spring-security-remoting.jar提供与 Spring Remoting 集成。
网页spring-security-web.jar包括网站安全的模块,提供网站认证服务和基于 URL 访问控制。
配置spring-security-config.jar包含安全命令空间解析代码。
LDAPspring-security-ldap.jarLDAP 验证和配置。
ACLspring-security-acl.jar对 ACL 访问控制表的实现。
CASspring-security-cas.jar对 CAS 客户端的安全实现。
OpenlDspring-security-openid.jar对 OpenID 网页验证的支持。
Testspring-security-test.jar对 Spring Security 的测试的支持。

2.核心类

在这里插入图片描述

2.1 Securitycontext

SecurityContext 中包含 当前正在访问系统的用户的详细信息,它只有以下两种方法。

  • getAuthentication():获取当前经过身份验证的主体或身份验证的请求令牌。
  • setAuthentication():更改或删除当前已验证的主体身份验证信息。

SecurityContext 的信息是由 SecurityContextHolder 来处理的。

2.2 SecurityContextHolder

SecurityContextHolder 用来保存 SecurityContext。最常用的是 getContext() 方法,用来获得当前 SecurityContext。

在这里插入图片描述
SecurityContextHolder 中定义了一系列的静态方法,而这些静态方法的内部逻辑是通过 SecurityContextHolder 持有的 SecurityContextHolderStrategy 实现的,如 clearContext()getContext()setContext()createEmptyContext()

SecurityContextHolderStrategy 的关键代码如下:

public interface SecurityContextHolderStrategy {
  void clearContext();
  Securitycontext getContext();
  void setContext(SecurityContext context);
  Securitycontext createEmptyContext();
}

2.2.1 strategy 实现

默认使用的 strategy 就是基于ThreadLocal 的 ThreadLocalSecurityContextHolderStrategy 来实现的。

除了上述提到的,Spring Security 还提供了 3 种类型的 strategy 来实现。

  • GlobalSecurityContextHolderStrategy:表示全局使用同一个 SecurityContext,如 C/S 结构的客户端。
  • InheritableThreadLocalSecurityContextHolderStrategy:使用 InheritableThreadLocal 来存放 Securitycontext,即子线程可以使用父线程中存放的变量。
  • ThreadLocalSecurityContextHolderStrategy: 使用 ThreadLocal 来存放 SecurityContext。

—般情况下,使用默认的 strategy 即可。但是,如果要改变默认的 strategy,Spring Security 提供了两种方法来改变 strategyName

SecurityContextHolder 类中有 3 种不同类型的 strategy, 分别为 MODE_THREADLOCALMODE_INHERITABLETHREADLOCALMODE_GLOBAL,关键代码如下:

public static final String MODE_THREADLOCAL = "MODE_THREADLOCAL"public static final String MODEJNHERITABLETHREADLOCAL = "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;

MODE_THREADLOCAL 是默认的方法。

如果要改变 strategy,则有下面两种方法:

  • 通过 SecurityContextHolder 的静态方法 setStrategyName(java.lang.String strategyName) 来改变需要使用的 strategy。
  • 通过系统属性(SYSTEM_PROPERTY)行指定,其中属性名默认为 spring.security. strategy,属性值为对应 strategy 的名称。

2.2.2 获取当前用户的 SecurityContext

Spring Security 使用一个 Authentication 对象来描述当前用户的相关信息。SecurityContextHolder 中持有的是当前用户的Securitycontext,而 SecurityContext 持有的是代表当前用户相关信息的 Authentication 的引用。

这个 Authentication 对象不需要自己创建,Spring Security 会自动创建相应的 Authentication 对象,然后赋值给当前的 SecurityContext。但是,往往需要在程序中获取当前用户的相关信息,比如最常见的是获取当前登录用户的用户名。在程序的任何地方,可以通过如下方式获取到当前用 户的用户名。

public String getCurrentUsername() {
  Object principal = SecurityContextHolder.getContext().getAuthentication().getPrincipal();
  if (principal instanceof UserDetails){
    return ((UserDetails) principal).getUsermame();
  } 
  if (principal instanceof Principal) {
    return ((Principal) principal).getName();
  }
  return String.valueOf(principal);
}
  • getAuthentication() 方法会返回认证信息。
  • getPrincipal() 方法返回身份信息,它是 UserDetails 对身份信息的封装。

获取当前用户的用户名,最简单的方式如下:

public String getCurrentUsername() (
  return SecurityContextHolder.getContext().getAuthentication().getName();
)

在调用 SecurityContextHolder.getContext() 获取 Securitycontext 时,如果对应的 Securitycontext 不存在,则返回空的 SecurityContext。

2.3 ProviderManager

ProviderManager 会维护 一个认证的列表,以便处理不同认证方式的认证,因为系统可能会存在多种认证方式,比如手机号、用户名密码、邮箱方式。

在认证时,如果 ProviderManager 的认证结果不是 null,则说明认证成功,不再进行其他方式的认证,并且作为认证的结果保存在 SecurityContext 中。如果不成功,则抛出错误信息 ProviderNotFoundException

2.4 DaoAuthenticationProvider

它是 AuthenticationProvider 最常用的实现,用来获取用户提交的用户名和密码,并进行正确性比对。如果正确,则返回一个数据库中的用户信息。

当用户在前台提交了用户名和密码后,就会被封装成 UsemamePasswordAuthenticationToken。

然后,DaoAuthenticationProvider 根据 retrieveUser 方法,交给 additionalAuthenticationChecks 方法完成 UsemamePasswordAuthenticationToken 和 UserDetails 密码的比对。如果这个方法没有抛出异常,则认为比对成功。

比对密码需要用到 PasswordEncoderSaltSource

2.5 UserDetails

UserDetails 是 Spring Security 的 用户实体类,包含用户名、密码、权限等信息。Spring Security 默认实现了内置的 User 类,供 Spring Security 安全认证使用。当然,也可以自己实现。

UserDetails 接口和 Authentication 接口很类似,都拥有 usernameauthorities。一定要区分清楚 Authentication 的 getCredentials() 与 UserDetails 中的 getPassword()前者用户提交的密码凭证,不一定是正确的,或数据库不一定存在;后者用户正确的密码,认证器要进行比对的就是两者是否相同。

Authentication 中的 getAuthorities() 方法是由 UserDetails 的 getAuthorities() 传递而形成的。UserDetails 的用户信息是经过 AuthenticationProvider 认证之后被填充的。

UserDetails 中提供了以下几种方法。

  • String getPassword():返回验证用户密码,无法返回则显示为 null
  • String getUsername():返回验证用户名,无法返回则显示为 null
  • boolean isAccountNonExpired():账户是否过期,过期无法验证。
  • boolean isAccountNonLocked():指定用户是否被锁定或解锁,锁定的用户无法逬行身份验证。
  • boolean isCredentialsNonExpired():指定是否已过期的用户的凭据(密码),过期的凭据无法认证。
  • boolean isEnabled():是否被禁用。禁用的用户不能进行身份验证。

在这里插入图片描述

2.6 UserDetailsService

用户相关的信息是通过 UserDetailsService 接口来加载的。该接口的唯一方法是 loadUserByUsername(String username),用来 根据用户名加载相关信息

这个方法的返回值是 UserDetails 接口,其中包含了用户的信息,包括用户名、密码、权限、是否启用、是否被锁定、是否过期等。

2.7 GrantedAuthority

GrantedAuthority 中只定义了一个 getAuthority() 方法。该方法返回一个字符串,表示对应权限的字符串。如果对应权限不能用字符串表示,则返回 null

GrantedAuthority 接口通过 UserDetailsService 进行加载,然后赋予 UserDetails。

Authentication 的 getAuthorities() 方法可以返回当前 Authentication 对象拥有的权限,其返回值是一个 GrantedAuthority 类型的数组。每一个 GrantedAuthority 对象代表赋予当前用户的一种权限。

2.8 Filter

Filter 类型
说明
SecurityContextPersistenceFilter它从 SecurityContextRepository 中取出用户认证信息。为了提高效率,避免每次请求都要查询认证信息,它会从 Session 中取出已认证的用户信息,然后将其放入 SecurityContextHolder 中,以便其他 Filter 使用。
WebAsyncManagerlntegrationFilter集成了 SecurityContext 和 WebAsyncManager,把 SecurityContext 设置到异步线程,使其也能获取到用户上下文认证信息。
HeaderWriterFilter它对请求的 Header 添加相应的信息。
CsrfFilter跨域请求伪造过滤器。通过客户端传过来的 token 与服务器端存储的 token 进行对比,来判断请求的合法性。
LogoutFilter匹配登出 URL。匹配成功后,退出用户,并清除认证信息。
UsernamePasswordAuthenticationFilter登录认证过滤器,默认是对 /login 的 POST 请求进行认证。该方法会调用 attemptAuthentication,尝试获取一个 Authentication 认证对象,以保存认证信息,然后转向下一个 Filter,最后调用 successfulAuthentication 执行认证后的事件。
AnonymousAuthenticationFilter如果 SecurityContextHolder 中的认证信息为空,则会创建一个匿名用户到 SecurityContextHolder 中。
SessionManagementFilter持久化登录的用户信息。用户信息会被保存到 Session、Cookie 或 Redis 中。

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

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

相关文章

刷题心得之位运算技巧 gcd 和 lcm

位运算 gcd 和 lcm 位运算技巧遍历 n 的所有子集, 不包括空集遍历 n 的所有子集, 包括空集提取出 n 二进制中第一次出现的1消除 n 二进制中第一次出现的1判断 n 是否是 2 的幂次方 gcd [最大公约数]lcm [最小公倍数] 位运算技巧 遍历 n 的所有子集, 不包括空集 #include <…

52.TFT_LCD液晶屏字符显示

&#xff08;1&#xff09;实验目标&#xff1a;在5寸显示屏&#xff08;800 * 480 60&#xff09;中央显示汉字&#xff08;黄色&#xff09;&#xff0c;且背景颜色为青色。 &#xff08;2&#xff09;代码编写&#xff1a; tft_ctrl模块&#xff1a; module tft_ctrl(inp…

电子电气架构---域控制器的软硬件趋势

我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 屏蔽力是信息过载时代一个人的特殊竞争力,任何消耗你的人和事,多看一眼都是你的不对。非必要不费力证明自己,无利益不试图说服别人,是精神上的节…

TiDB-从0到1-sync-diff-inspector数据校验工具

TiDB从0到1系列 TiDB-从0到1-体系结构TiDB-从0到1-分布式存储TiDB-从0到1-分布式事务TiDB-从0到1-MVCCTiDB-从0到1-部署篇TiDB-从0到1-配置篇TiDB-从0到1-集群扩缩容TiDB-从0到1-数据导出导入TiDB-从0到1-BR工具 一、sync-diff-inspector工具 sync-diff-inspector是TiDB原生…

【北京迅为】《i.MX8MM嵌入式Linux开发指南》-第三篇 嵌入式Linux驱动开发篇-第六十二章 定时器按键消抖实验

i.MX8MM处理器采用了先进的14LPCFinFET工艺&#xff0c;提供更快的速度和更高的电源效率;四核Cortex-A53&#xff0c;单核Cortex-M4&#xff0c;多达五个内核 &#xff0c;主频高达1.8GHz&#xff0c;2G DDR4内存、8G EMMC存储。千兆工业级以太网、MIPI-DSI、USB HOST、WIFI/BT…

详解Mysql InnoDB引擎 04

文章目录 1. InnoDB 简介2. 逻辑存储结构2.1 表空间 idb文件2.2 段2.3 区 1M2.4 页 16KB2.5 行 3. 架构3.1 内存结构3.1.1 Buffer Pool 缓冲池3.1.2 Change Buffer 更改缓冲区3.1.3 Adaptive Hash Index3.1.4 Log Buffer 3.2 磁盘结构 4. 后台线程5. 事务原理5.1 redo log 重做…

Pytorch深度学习实践(9)卷积神经网络

卷积神经网络 全连接神经网络 神经网络中全部是线性模型&#xff0c;是由线性模型串联起来的 全连接网络又叫全连接层 卷积神经网络 在全连接神经网络中&#xff0c;由于输入必须是一维向量&#xff0c;因此在处理图像时必须要对图像矩阵进行拉伸成一维的形式&#xff0c;…

视觉巡线小车(STM32+OpenMV)——总结

文章目录 目录 文章目录 前言 一、效果展示 二、完整流程 1、STM32CubeMX配置 2、Keil编辑 3、硬件接线 4、参数调试 5、图像处理调试 三、总结 前言 基于前面的系列文章&#xff0c;已基本介绍完了基于STM32OpenMV的视觉巡线小车&#xff0c;本文将以小编自己的小车…

BACnet物联网关BL103:Modbus协议转BACnet/MSTP

随着物联网技术在楼宇自动化与暖通控制系统中的迅猛发展&#xff0c;构建一种既经济高效又高度可靠的协议转换物联网关成为了不可或缺的核心硬件组件。在此背景下&#xff0c;我们钡铼特别推荐一款主流的BAS&#xff08;楼宇自动化系统&#xff09;与BACnet物联网关——BL103&a…

小世界特性解析——聚类系数与平均路径长度的奥秘

小世界特性解析——聚类系数与平均路径长度的奥秘 小世界特性的核心衡量指标 小世界特性&#xff0c;这一复杂网络中的重要概念&#xff0c;主要通过两个关键指标来衡量&#xff1a;聚类系数和平均路径长度。这两个指标共同揭示了网络结构的紧密程度和信息传播的效率。 聚类…

echarts没数据的时候,页面显示暂无数据

echarts没数据的时候&#xff0c;页面显示暂无数据 给个if判断 let option{} if(data.length0){ //没有数据或者数据不合法,显示暂无数据option {title: {text: 暂无数据,x: center,y: center,textStyle: {fontFamily: Manteka,fontSize: 12,fontWeight: normal,color: #333…

使用 Copilot 对 OneDrive 文档分享进行摘要

对于大量使用onedrive进行资料分享的用户而言&#xff0c;对分享的文件进行简要说明并提供给对方&#xff0c;是一个基本素养。 在以往&#xff0c;他们只能阅读文件名然后靠回忆进行撰写&#xff0c;或者打开每一个文档通读全文然后再关闭返回并撰写摘要。 当用户在 SharePo…

Java聚合快递小程序对接云洋系统程序app源码

​一场物流效率的革命 引言&#xff1a;物流新时代的序章 在数字化浪潮席卷各行各业的今天&#xff0c;物流行业也迎来了前所未有的变革。为了进一步提升物流效率&#xff0c;优化用户体验&#xff0c;聚合快递系统与云洋系统小程序的对接成为了行业内外关注的焦点。这一创新…

基于JSP的毕业生就业信息管理系统

你好&#xff0c;我是专注于信息系统开发的码农小野&#xff01;如果你对毕业生就业信息管理有需求&#xff0c;欢迎联系我。 开发语言&#xff1a;JSP 数据库&#xff1a;MySQL 技术&#xff1a;JSP技术 SSM框架 工具&#xff1a;Eclipse、Maven、Navicat 系统展示 首页…

登录案例(JAVA)

练习1 package lx2;import java.io.BufferedReader; import java.io.FileNotFoundException; import java.io.FileReader; import java.io.IOException; import java.util.ArrayList; import java.util.Scanner;public class demo1 {/*需求&#xff1a;写一个登陆小案例。步骤…

Hive环境搭建(内置数据库)

实验目的】 1) 了解hive的作用 2) 熟练hive的配置过程&#xff08;内置数据库&#xff09; 【实验原理】 Hive的架构是由Client、Metastore、Driver、Compiler构成&#xff0c;执行流程是编译器可以将一个Hive QL转换成操作符&#xff0c;操作符是Hive中的最小处理单元。…

【BUG】已解决:UnicodeDecodeError: ‘utf-8’ codec can’t decode bytes in position 10

UnicodeDecodeError: ‘utf-8’ codec can’t decode bytes in position 10 目录 UnicodeDecodeError: ‘utf-8’ codec can’t decode bytes in position 10 【常见模块错误】 【解决方案】 欢迎来到英杰社区https://bbs.csdn.net/topics/617804998 欢迎来到我的主页&#x…

torch fbgemm.dll 报错

这里写自定义目录标题 OSError: [WinError 126] The specified module could not be found. Error loading \"c:\\Users\\Noor\\anaconda3\\envs\\DL\\Lib\\site-packages\\torch\\lib\\fbgemm.dll\" or one of its dependencies."https://github.com/lucasg/De…

在VMware创建Ubuntu24

目录 一、创建虚拟机 1. 自定义创建虚拟机 2. 设置虚拟机兼容 3. 选择镜像 4. 命名虚拟机&#xff0c;选择存放位置 5. 处理器配置 6. 内存配置 7. 网络类型配置 8. I/O控制器类型 9. 磁盘配置 10. 完成虚拟机创建 二、Ubuntu安装 1. 进入虚拟机中进行ubuntu的安…

java算法day25

java算法day25 广度优先搜索岛屿数量深搜岛屿数量广搜 广度优先搜索 核心&#xff1a;从起点出发&#xff0c;以起始点为中心一圈一圈进行搜索&#xff0c;一旦遇到终点&#xff0c;记录之前走过的节点就是一条最短路。搜索的方式是上下左右 一张图说明白模拟过程&#xff1…