一文入门SpringSecurity 5

news2024/11/22 15:54:27

目录

提示

Apache Shiro和Spring Security

认证和授权

RBAC

Demo

环境

Controller

引入Spring Security

初探Security原理

认证授权图示​编辑

图中涉及的类和接口

流程总结


提示

Spring Security源码的接口名和方法名都很长,看源码的时候要见名知意,有必要细看接口名和方法名,另外可以借助流程图,调试追踪代码,有助于理解学习!

Apache Shiro和Spring Security

​Spring Security是一个高度可定制的身份验证(认证)和访问控制(授权)框架,它是用于保护基于Spring的应用程序的实际标准,相比与另外一个安全框架Shiro,它提供了更丰富的功能,社区资源也比Shiro丰富。

  • Shiro轻量级,不依赖Spring,是第三方框架,简单而灵活,可以用于非Web环境!
  • Security重量级,依赖Spring,控制粒度更细,老版本不能脱离Web,新版本可以
  • Spring Boot 2默认使用Security 5,要求JDK至少是8
  • Spring Boot 3默认使用Security 6,要求JDK至少是17
  • Security 5和Security 6的区别之一就是5到6废弃了WebSecurityConfigurerAdapter类,在Security 5编写配置类需要继承WebSecurityConfigurerAdapter并重写某些方法,但是在Security 6已经不需要了

Spring Security:升级已弃用的 WebSecurityConfigurerAdapter - spring 中文网

从 Spring Security 5 迁移到 Spring Security 6/Spring Boot 3 - spring 中文网

认证和授权

认证(Authentication):验证当前访问系统的是不是本系统的用户,并且要确认具体是哪个用户

​授权(Authorization):经过认证后判断当前用户是否有权限进行某个操作

注:Authentication和Authorization拼写很像,有必要分清,后面看源代码方便!

RBAC

Role-Based Access Control 基于角色的访问控制

把权限打包给角色(角色拥有一组权限),给用户分配角色(用户拥有多个角色)

最少包括五张表 (用户表、角色表、用户角色表、权限表、角色权限表)

Demo

环境

Spring Boot:2.7.2

SpringSecurity:5+

JDK:1.8

Controller

@RestController
@RequestMapping("/admin")
public class AdminController {
    @GetMapping("/query")
    public String queryInfo(){
        return "I am a admin";
    }
}

 ​​​​​​可以直接访问

引入Spring Security

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>

再次访问时默认出现了该登陆界面,默认用户是user,密码默认在控制台生成 ,成功登陆后才会放行。Spring Security默认拦截了除登录、退出之外的所有请求。显示的登录和退出表单是Security默认生成的。

(前端页面样式bootstrap.min.css是一个CDN地址,需要魔法,所以加载很慢) 

初探Security原理

Spring Security底层是基于Servlet的过滤器链,默认共有16个过滤器,这里面我们只需要重点关注两个过滤器即可:UsernamePasswordAuthenticationFilter负责登录认证,FilterSecurityInterceptor负责权限授权。

认证授权图示

图中涉及的类和接口

  • UsernamePasswordAuthenticationFilter类

    抽象类AbstractAuthenticationProcessingFilter的子类,是常用的用户名和密码认证方式的主要处理类,该类中将用请求信息封装为初步的Authentication(Authentication实际上是一个接口,它的实现类是UsernamePasswordAuthenticationToken),此时最多只有用户名和密码,在登录认证成功之后又会生成一个包含用户权限等信息的更全面的 Authentication 对象,然后把它保存在 SecurityContextHolder 所持有的 SecurityContext 中。

  • AuthenticationManager接口

    public interface AuthenticationManager {
        Authentication authenticate(Authentication authentication) throws AuthenticationException;
    }

    用来处理Authentication请求的接口。在其中只定义了一个方法 authenticate(),该方法只接收一个代表认证请求的 Authentication 对象作为参数,如果认证成功,则会返回一个封装了当前用户权限等信息的 Authentication 对象。

  • ProviderManager类

    public class ProviderManager implements AuthenticationManager, MessageSourceAware, InitializingBean 

    AuthenticationManager接口的实现类AuthenticationManager接口不直接自己处理认证请求,而是委托给ProviderManager所配置的AuthenticationProvider 列表,而ProviderManager的作用就是管理这个AuthenticationProvider列表,管理的方式是通过for循环去遍历该列表,因为不同的登录逻辑(表单登录、qq登录、邮箱登录)是不一样的,那么AuthenticationProvider列表就要支持不同的Authentication。
    信息验证的逻辑都是在AuthenticationProvider里面,会依次使用每一个 AuthenticationProvider 进行认证,如果有一个 AuthenticationProvider 认证后的结果不为 null,则表示该 AuthenticationProvider 已经认证成功,之后的 AuthenticationProvider 将不再继续认证。然后直接以该 AuthenticationProvider 的认证结果作为 ProviderManager 的认证结果。如果所有的 AuthenticationProvider 的认证结果都为 null,则表示认证失败,将抛出一个 ProviderNotFoundException

  • AuthenticationProvider接口
    该接口被实现为抽象类AbstractUserDetailsAuthenticationProvider,然后DaoAuthenticationProvider类继承该抽象类,并拥有一个UserDetailsService的变量

    public abstract class AbstractUserDetailsAuthenticationProvider implements AuthenticationProvider, InitializingBean, MessageSourceAware
    
    public class DaoAuthenticationProvider extends AbstractUserDetailsAuthenticationProvider
  • UserDetailsService接口
    public interface UserDetailsService {
        UserDetails loadUserByUsername(String username) throws UsernameNotFoundException;
    }
    加载用户数据的核心接口,可以自定义从数据库加载数据或者从内存加载临时用户(InMemory),登录认证的时候 Spring Security 会通过 UserDetailsService 的 loadUserByUsername() 方法获取对应的 UserDetails 类型的用户信息进行认证,认证通过后会将用户信息封装为UserDetails接口的实现类User并赋给认证通过的 Authentication 的 principal,然后再把该 Authentication 存入到 SecurityContext 中。
  • InMemoryUserDetailsManager类
    该类是UserDetailsService接口的实现类,作用是从内存中加载用户,也就是说用户是在代码中提前写好的,程序运行后被加载到内存,不是从数据库中取的没有持久化,如果是从数据库加载用户就不用这个类了。该类有一个方法是

    private User createUserDetails(String name, UserAttribute attr),返回值是User类型

  • UserDetails接口

    public interface UserDetails extends Serializable 

    提供用户核心信息的接口,通过 UserDetailsService 的 loadUserByUsername() 方法获取,然后将该 UserDetails 赋给认证通过的 Authentication 的 principal。

  • User类

    public class User implements UserDetails, CredentialsContainer 

    UserDetails接口的实现类,User类也是security的默认用户类,我们可以继承该类对其方法重写

  • SecurityContextHolder类

    用来保存 SecurityContext 的,SecurityContext 中含有当前正在访问系统的用户的详细信息。默认情况下,SecurityContextHolder 使用 ThreadLocal 来保存 SecurityContext,这也就意味着在处于同一线程中的方法中我们可以从 ThreadLocal 中获取到当前的 SecurityContext。因为线程池的原因,如果我们每次在请求完成后都将 ThreadLocal 进行清除的话,那么我们把 SecurityContext 存放在 ThreadLocal 中还是比较安全的。这些工作 Spring Security 已经自动为我们做了,即在每一次 request 结束后都将清除当前线程的 ThreadLocal。 

流程总结

用户填写的用户名密码传到后端,进入Security的过滤器链进行验证,验证流程为:

进入UsernamePasswordAuthenticationFilter,里面有一个attemptAuthentication方法,该方法会生成一个UsernamePasswordAuthenticationToken,也就是一个凭证Authentication,这个Authentication只包含了用户名、密码这些基础信息,没有权限等其他信息,然后Authentication作为参数被传到AuthenticationManager接口的实现类ProviderManager类authenticate方法进行认证,ProviderManager类中有一个List<AuthenticationProvider> 列表AuthenticationProvider是接口,AbstractUserDetailsAuthenticationProvider是接口的抽象类,DaoAuthenticationProvider是实现类),该列表存放着不同的登录逻辑AuthenticationProvider,通过for循环去遍历该列表,信息验证的逻辑都是在AuthenticationProvider里面,会依次使用每一AuthenticationProvider进行认证,如果有一个 AuthenticationProvider 认证后的结果不为 null,则表示该AuthenticationProvider已经认证成功,之后的 AuthenticationProvider 将不再继续认证。然后直接以该 AuthenticationProvider 的认证结果作为 ProviderManager 的认证结果。如果所有的 AuthenticationProvider 的认证结果都为 null,则表示认证失败,将抛出一个 ProviderNotFoundException。

DaoAuthenticationProvider内部的认证逻辑:它有一个retrieveUser方法,该方法调用UserDetailsService().loadUserByUsername从数据库获取用户信息,并返回一个UserDetails类型的对象,它含有用户的详细信息,如用户权限等等,然后将UserDetails对象和Authentication校验,成功后会把UserDetails中的信息填入到Authentication,一个最终的Authentication就产生了,它会被保存到安全上下文中!

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

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

相关文章

docker笔记4-镜像理解

docker笔记4-镜像理解 一、镜像原理之联合文件系统二、镜像原理之分层理解三、commit镜像 一、镜像原理之联合文件系统 UnionFS&#xff08;联合文件系统&#xff09;: Union文件系统&#xff08;UnionFS&#xff09;是一种分层、轻量级并且高性能的文件系统&#xff0c;它支持…

深入了解路由器工作原理:从零开始的简单讲解

简介 在现代网络中&#xff0c;路由器扮演着至关重要的角色。它不仅连接了不同的设备&#xff0c;还确保数据能够准确地传输到目的地。本文将带你深入探讨路由器的工作原理&#xff0c;帮助网络基础小白们理解这一重要设备的基本功能。 路由器的构成 路由器是一种具有多个输入…

云计算实训12——配置web服务器、配置客户端服务器、配置DNS服务、实现DNS域名解析

一、配置web服务器 准备操作 首先在正式配置之前需要做以下操作 关闭防火墙 systemctl stop firewalld 永久关闭防火墙 systemctl disable firewalld 关闭selinux setenforce 0 永久关闭selinux vim /etc/selinux/config selinuxpermissive 还需要保证能够正常ping通www.bai…

使用uniapp开发小程序(基础篇)

本文章只介绍微信小程序的开发流程&#xff0c;如果需要了解其他平台的开发的流程的话&#xff0c;后续根据情况更新相应的文章,也可以根据uniapp官网的链接了解不同平台的开发流程 HBuilderX使用&#xff1a;https://uniapp.dcloud.net.cn/quickstart-hx.html 开发工具 开始…

【Django】在vscode中运行调试Django项目(命令及图形方式)

文章目录 命令方式图形方式默认8000端口设置自定义端口 命令方式 python manage.py runserver图形方式 默认8000端口 设置自定义端口

LIS系统源码,实验室管理信息系统LIS,.Net C#语言开发,支持DB2,Oracle,MS SQLServer等主流数据库

实验室管理信息系统LIS源码&#xff0c;采用.Net C#语言开发&#xff0c;C/S架构。支持DB2&#xff0c;Oracle&#xff0c;MS SQLServer等主流数据库。&#xff08;LIS系统全套商业源码&#xff0c;自主版权&#xff0c;多家大型综合医院应用案例&#xff0c;适合二次开发&…

【Android】ListView和RecyclerView知识总结

文章目录 ListView步骤适配器AdpterArrayAdapterSimpleAdapterBaseAdpter效率问题 RecyclerView具体实现不同布局形式的设置横向滚动瀑布流网格 点击事件 ListView ListView 是 Android 中的一种视图组件&#xff0c;用于显示可滚动的垂直列表。每个列表项都是一个视图对象&…

spring IOC DI --DI详解

T04BF &#x1f44b;专栏: 算法|JAVA|MySQL|C语言 &#x1faf5; 今天你敲代码了吗 文章目录 4.3 DI详解4.3.1属性注入4.3.2 构造方法注入4.3.3 Setter注入4.3.4 三种注入优缺点 4.4 Autowired 存在问题PrimaryQualifier 4.3 DI详解 依赖注入是一个过程,是指Ioc容器在创建Bean…

在 Android 上实现语音命令识别:详细指南

在 Android 上实现语音命令识别:详细指南 语音命令识别在现代 Android 应用中变得越来越普遍。它允许用户通过自然语言与设备进行交互,从而提升用户体验。本文将详细介绍如何在 Android 上实现语音命令识别,包括基本实现、带有占位槽位的命令处理,以及相关的配置和调试步骤…

C++:模板(函数模板,类模板)

目录 泛型编程 函数模板 函数模板格式 函数模板的原理 函数模板的实例化 类模板 类模板格式 类模板实例化 模板分为函数模板和类模板 在C中使用模板可以让我们实现泛型编程 泛型编程 如果我们需要实现一个加法add函数&#xff0c;那么会怎么实现呢&#xff1f; int…

AI学习记录 - 规范化输出对接现有系统的实例

假设我们有一个学生管理系统&#xff0c;通过prompt提示&#xff0c;格式化输出然后对接现有系统&#xff0c;也是通过react实现&#xff0c;因为这只是一个知识分享&#xff0c;没弄太复杂&#xff08;使用react实现&#xff09;。 学生管理系统 1、设计好prompt getMemory()…

大屏数据看板一般是用什么技术实现的?

我们看到过很多企业都会使用数据看板&#xff0c;那么大屏看板的真正意义是什么呢&#xff1f;难道只是为了好看&#xff1f;答案当然不仅仅是。 大屏看板不仅可以提升公司形象&#xff0c;还可以提升企业的管理层次。对于客户&#xff0c;体现公司实力和品牌形象&#xff0c;…

Linux shell编程学习笔记66:ping命令 超详细的选项说明

0 前言 网络信息是电脑网络信息安全检查中的一块重要内容&#xff0c;Linux和基于Linux的操作系统&#xff0c;提供了很多的网络命令&#xff0c;今天我们研究最常用的ping命令。 1 ping命令 的功能、格式和选项说明 1.1 ping命令 的功能 简单来说&#xff0c; ping 命令 会…

编写SpringBoot的自定义starter包

starter项目 先来看一下Starter的官方解释&#xff1a; Spring Boot Starter 是一种方便的依赖管理方式&#xff0c;它封装了特定功能或技术栈的所有必要依赖项和配置&#xff0c;使得开发者可以快速地将这些功能集成到Spring Boot项目中。Spring Boot官方提供了一系列的Star…

首次 Cloudberry Database 社区聚会 · 北京站,8月3日,诚邀

近期 Greenplum 源码归档及走向闭源在圈内讨论火热&#xff0c;原有开源用户面临断档风险。作为 Greenplum 衍生版和开源替代&#xff0c;Cloudberry Database 由原厂核心开发者打造&#xff0c;与其保持兼容&#xff0c;并且具备更新内核和更丰富功能。Cloudberry Database 逐…

代理协议解析:如何根据需求选择HTTP、HTTPS或SOCKS5?

代理IP协议是一种网络代理技术&#xff0c;可以实现隐藏客户端IP地址、加速网站访问、过滤网络内容、访问内网资源等功能。常用的IP代理协议主要有Socks5代理、HTTP代理、HTTPS代理这三种。代理IP协议主要用于分组交换计算机通信网络的互联系统中使用&#xff0c;只负责数据的路…

【MATLAB实战】基于UNet的肺结节的检测

数据&#xff1a; 训练过程图 算法简介&#xff1a; UNet网络是分割任务中的一个经典模型,因其整体形状与"U"相似而得名,"U"形结构有助于捕获多尺度信息,并促进了特征的精确重建&#xff0c;该网络整体由编码器,解码器以及跳跃连接三部分组成。 编码器由…

UE4/5 对话系统

参考教程&#xff1a;UE4甜筒教艺术生学蓝图#21.UE4对话系统(1)--唠嗑案例展示_哔哩哔哩_bilibili 说来惭愧两年前看的教程&#xff0c;现在才记录一下&#xff0c;很好的教程推荐大家观看 1.首先创建两个枚举&#xff0c;内容如下 2.创建三个结构体&#xff0c;内容如下 3.再…

SSRF:服务端请求伪造

SSRF漏洞原理 SSRF漏洞通常是因为服务端应用程序提供了从其他服务器获取数据的功能&#xff0c;但未对目标地址或协议进行适当的过滤和限制。攻击者可以通过这个漏洞发送构造好的恶意请求&#xff0c;让服务器以自己的身份去访问其他资源&#xff0c;与文件包含漏洞有些许相似…

遍历dom元素下面的子元素的方法,vue中原始标签的ref得到是该元素的dom及下面包含的子dom,与组件ref是引用不同

研究到这个的目的来源是 想用div 遍历方式 替代之前的table tr td 那种框选功能&#xff0c;觉得div灵活&#xff0c;可以随便在外面套层&#xff0c;td与tr之间就不能加div加了布局就乱&#xff0c;然后使用之前的原理&#xff08; const cellList tableIdR.value.querySelec…