SpringSecurity在SpringBoot中的自动装配

从SpringBoot的自动装配原理入手

  1. 找到META-INFO下的spring.factories文件

SpringSecurity作为Spring的亲儿子,自然在spring-boot-autoconfigure下的spring.factories文件中配置了

org.springframework.boot.autoconfigure.security.servlet.SecurityAutoConfiguration,\
org.springframework.boot.autoconfigure.security.servlet.UserDetailsServiceAutoConfiguration,\
org.springframework.boot.autoconfigure.security.servlet.SecurityFilterAutoConfiguration,\

UserDetailsServiceAutoConfiguration

@Configuration(proxyBeanMethods = false
)
//条件注解
@ConditionalOnClass({AuthenticationManager.class})
@ConditionalOnBean({ObjectPostProcessor.class})
//提供拓展,没有提供以下三个实现类才使用默认的
@ConditionalOnMissingBean(value = {AuthenticationManager.class, AuthenticationProvider.class, UserDetailsService.class},type = {"org.springframework.security.oauth2.jwt.JwtDecoder", "org.springframework.security.oauth2.server.resource.introspection.OpaqueTokenIntrospector"}
)
public class UserDetailsServiceAutoConfiguration {//密码不加密表示private static final String NOOP_PASSWORD_PREFIX = "{noop}";private static final Pattern PASSWORD_ALGORITHM_PATTERN = Pattern.compile("^\\{.+}.*$");private static final Log logger = LogFactory.getLog(UserDetailsServiceAutoConfiguration.class);public UserDetailsServiceAutoConfiguration() {}@Bean@ConditionalOnMissingBean(type = {"org.springframework.security.oauth2.client.registration.ClientRegistrationRepository"})@Lazypublic InMemoryUserDetailsManager inMemoryUserDetailsManager(SecurityProperties properties, ObjectProvider<PasswordEncoder> passwordEncoder) {//读取以spring.security开头的配置文件SecurityProperties.User user = properties.getUser();List<String> roles = user.getRoles();return new InMemoryUserDetailsManager(new UserDetails[]{User.withUsername(user.getName()).password(this.getOrDeducePassword(user, (PasswordEncoder)passwordEncoder.getIfAvailable())).roles(StringUtils.toStringArray(roles)).build()});}private String getOrDeducePassword(SecurityProperties.User user, PasswordEncoder encoder) {String password = user.getPassword();if (user.isPasswordGenerated()) {logger.info(String.format("%n%nUsing generated security password: %s%n", user.getPassword()));}return encoder == null && !PASSWORD_ALGORITHM_PATTERN.matcher(password).matches() ? "{noop}" + password : password;}
}
//标记读取配置文件夹信息
@ConfigurationProperties(prefix = "spring.security"
)
public class SecurityProperties {public static final int BASIC_AUTH_ORDER = 2147483642;public static final int IGNORED_ORDER = Integer.MIN_VALUE;public static final int DEFAULT_FILTER_ORDER = -100;private final Filter filter = new Filter();private User user = new User();public SecurityProperties() {}public User getUser() {return this.user;}public Filter getFilter() {return this.filter;}public static class User {//如果没有配置,用户名默认user,密码uuidprivate String name = "user";private String password = UUID.randomUUID().toString();private List<String> roles = new ArrayList();private boolean passwordGenerated = true;public User() {}public String getName() {return this.name;}public void setName(String name) {this.name = name;}public String getPassword() {return this.password;}public void setPassword(String password) {if (StringUtils.hasLength(password)) {this.passwordGenerated = false;this.password = password;}}public List<String> getRoles() {return this.roles;}public void setRoles(List<String> roles) {this.roles = new ArrayList(roles);}public boolean isPasswordGenerated() {return this.passwordGenerated;}}public static class Filter {private int order = -100;private Set<DispatcherType> dispatcherTypes;public Filter() {this.dispatcherTypes = new HashSet(Arrays.asList(DispatcherType.ASYNC, DispatcherType.ERROR, DispatcherType.REQUEST));}public int getOrder() {return this.order;}public void setOrder(int order) {this.order = order;}public Set<DispatcherType> getDispatcherTypes() {return this.dispatcherTypes;}public void setDispatcherTypes(Set<DispatcherType> dispatcherTypes) {this.dispatcherTypes = dispatcherTypes;}}
}

SecurityFilterAutoConfiguration

约定大于配置,这里的内容就相当于在web.xml配置文件中配置springSecurityFilterChain的过程由spring自动实现.spring自动注入DelegatingFilterProxy对象,这样就可以将security中的过滤器切到spring中,在请求的时候会被DelegatingFilterProxyRegistrationBean拦截,然后去执行security中的过滤器链。


@Configuration(proxyBeanMethods = false
)
//web项目才加载
@ConditionalOnWebApplication(type = Type.SERVLET
)
@EnableConfigurationProperties({SecurityProperties.class})
@ConditionalOnClass({AbstractSecurityWebApplicationInitializer.class, SessionCreationPolicy.class})
//SecurityAutoConfiguration之后执行
@AutoConfigureAfter({SecurityAutoConfiguration.class})
public class SecurityFilterAutoConfiguration {//名字private static final String DEFAULT_FILTER_NAME = "springSecurityFilterChain";public SecurityFilterAutoConfiguration() {}/*** 创建DelegatingFilterProxyRegistrationBean对象注入到spring容器中* @param securityProperties* @return*/@Bean@ConditionalOnBean(name = {"springSecurityFilterChain"})public DelegatingFilterProxyRegistrationBean securityFilterChainRegistration(SecurityProperties securityProperties) {//创建DelegatingFilterProxy对象DelegatingFilterProxyRegistrationBean registration = new DelegatingFilterProxyRegistrationBean("springSecurityFilterChain", new ServletRegistrationBean[0]);registration.setOrder(securityProperties.getFilter().getOrder());registration.setDispatcherTypes(this.getDispatcherTypes(securityProperties));return registration;}private EnumSet<DispatcherType> getDispatcherTypes(SecurityProperties securityProperties) {return securityProperties.getFilter().getDispatcherTypes() == null ? null : (EnumSet)securityProperties.getFilter().getDispatcherTypes().stream().map((type) -> {return DispatcherType.valueOf(type.name());}).collect(Collectors.toCollection(() -> {return EnumSet.noneOf(DispatcherType.class);}));}
}

创建DelegatingFilterProxy的过程实际是通过ServletContextInitializer接口实现的,有一个方法onStartup,有一个实现类RegistrationBean

public abstract class RegistrationBean implements ServletContextInitializer, Ordered {private static final Log logger = LogFactory.getLog(RegistrationBean.class);private int order = Integer.MAX_VALUE;private boolean enabled = true;public RegistrationBean() {}public final void onStartup(ServletContext servletContext) throws ServletException {String description = this.getDescription();if (!this.isEnabled()) {logger.info(StringUtils.capitalize(description) + " was not registered (disabled)");} else {//注册this.register(description, servletContext);}}protected abstract String getDescription();protected abstract void register(String description, ServletContext servletContext);public void setEnabled(boolean enabled) {this.enabled = enabled;}public boolean isEnabled() {return this.enabled;}public void setOrder(int order) {this.order = order;}public int getOrder() {return this.order;}
}

注册逻辑在父类DynamicRegistrationBean中

public abstract class DynamicRegistrationBean<D extends Registration.Dynamic> extends RegistrationBean {private static final Log logger = LogFactory.getLog(RegistrationBean.class);private String name;private boolean asyncSupported = true;private Map<String, String> initParameters = new LinkedHashMap();public DynamicRegistrationBean() {}public void setName(String name) {Assert.hasLength(name, "Name must not be empty");this.name = name;}public void setAsyncSupported(boolean asyncSupported) {this.asyncSupported = asyncSupported;}public boolean isAsyncSupported() {return this.asyncSupported;}public void setInitParameters(Map<String, String> initParameters) {Assert.notNull(initParameters, "InitParameters must not be null");this.initParameters = new LinkedHashMap(initParameters);}public Map<String, String> getInitParameters() {return this.initParameters;}public void addInitParameter(String name, String value) {Assert.notNull(name, "Name must not be null");this.initParameters.put(name, value);}protected final void register(String description, ServletContext servletContext) {//生成DelegatingFilterProxy对象D registration = this.addRegistration(description, servletContext);if (registration == null) {logger.info(StringUtils.capitalize(description) + " was not registered (possibly already registered?)");} else {//在其父类AbstractFilterRegistrationBean中配置拦截/*请求this.configure(registration);}}protected abstract D addRegistration(String description, ServletContext servletContext);protected void configure(D registration) {registration.setAsyncSupported(this.asyncSupported);if (!this.initParameters.isEmpty()) {registration.setInitParameters(this.initParameters);}}protected final String getOrDeduceName(Object value) {return this.name != null ? this.name : Conventions.getVariableName(value);}
}

跟踪代码发现实际调用的了DelegatingFilterProxyRegistrationBean的getFilter方法

public class DelegatingFilterProxyRegistrationBean extends AbstractFilterRegistrationBean<DelegatingFilterProxy> implements ApplicationContextAware {private ApplicationContext applicationContext;private final String targetBeanName;public DelegatingFilterProxyRegistrationBean(String targetBeanName, ServletRegistrationBean<?>... servletRegistrationBeans) {super(servletRegistrationBeans);Assert.hasLength(targetBeanName, "TargetBeanName must not be null or empty");this.targetBeanName = targetBeanName;this.setName(targetBeanName);}public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {this.applicationContext = applicationContext;}protected String getTargetBeanName() {return this.targetBeanName;}//创建DelegatingFilterProxy实例对象public DelegatingFilterProxy getFilter() {return new DelegatingFilterProxy(this.targetBeanName, this.getWebApplicationContext()) {protected void initFilterBean() throws ServletException {}};}private WebApplicationContext getWebApplicationContext() {Assert.notNull(this.applicationContext, "ApplicationContext be injected");Assert.isInstanceOf(WebApplicationContext.class, this.applicationContext);return (WebApplicationContext)this.applicationContext;}
}

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

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

相关文章

ELFK简介

&#x1f468;‍&#x1f393;博主简介 &#x1f3c5;CSDN博客专家   &#x1f3c5;云计算领域优质创作者   &#x1f3c5;华为云开发者社区专家博主   &#x1f3c5;阿里云开发者社区专家博主 &#x1f48a;交流社区&#xff1a;运维交流社区 欢迎大家的加入&#xff01…

下载linux的吐槽

本来这几天放假了&#xff0c;想下一个linux玩一玩 教程&#xff08;我就是根据这个教程进行下载的&#xff0c;但是呢在进行修改BIOS 模式的 地方遇见了困难&#xff0c;也许是电脑修过的原因&#xff0c;我狂按F12 以及 FnF12都没有BIOS设置&#xff0c;只有一个让我选择用w…

吉时利KEITHLEY KI-488驱动和说明

吉时利KEITHLEY KI-488驱动和说明

HCIE之IPV6三大动态协议ISIS BGP (十五)

IPV6 1、三大动态路由协议ipv61.1、ISIS1.1.1、ISIS多拓扑实验&#xff08;需要详细看下lsdb verbose&#xff09;1.2、ISIS TLV简单总结 1.2、BGP 2、IPv6 隧道技术2.1、ipv6手工隧道2.1.1、ipv6 gre手工隧道2.1.1.1、 ipv6、ipv4基础配置&#xff08;省略&#xff09;2.1.1.2…

多语言版在线出租车预订完整源码+用户应用程序+管理员 Laravel 面板+ 司机应用程序最新版源码

源码带PHP后台客户端源码 Flutter 是 Google 开发的一款开源移动应用开发 SDK。它用于开发 Android 和 iOS 应用&#xff0c;也是为 Google Fuchsia 创建应用的主要方法。Flutter 小部件整合了所有关键的平台差异&#xff0c;例如滚动、导航、图标和字体&#xff0c;可在 iOS 和…

【Linux】进程的概念 + 查看进程

前言&#xff1a; 在前面我们学习了Liunx的基本指令和权限相关知识&#xff0c;还有基本工具的使用&#xff0c;有了以上的基础知识我们本章将正式接触Linux操作系统。 目录 1.冯诺依曼体系结构1.1 内存存在的意义1.2 程序加载到内存的含义1.3 程序的预加载&#xff1a; 2 .认识…

基于支持向量机、孤立森林和LSTM自编码器的机械状态异常检测(MATLAB R2021B)

异常检测通常是根据已有的观测数据建立正常行为模型&#xff0c;从而将不同机制下产生的远离正常行为的数据划分为异常类&#xff0c;进而实现对异常状态的检测。常用的异常检测方法主要有&#xff1a;统计方法、信息度量方法、谱映射方法、聚类方法、近邻方法和分类方法等。 …

OpenGL笔记七之顶点数据绘制命令和绘制模式

OpenGL笔记七之顶点数据绘制命令和绘制模式 —— 2024-07-07 杭州 下午 总结自bilibili赵新政老师的教程 文章目录 OpenGL笔记七之顶点数据绘制命令和绘制模式1.OpenGL版本号更改和编译更改2.GL_TRIANGLES模式绘制一个三角形、支持NFC坐标随窗口缩放2.1.三个点2.2.四个点从0号…

中霖教育:环评工程师的薪资待遇怎么样?

【中霖教育怎么样】【中霖教育靠谱吗】 想要考环评工程师&#xff0c;但是不知道这个证书在行业内的发展前景是怎样的&#xff0c;中霖来为大家解答一下! 环评工程师&#xff0c;作为当前环境工程领域中非常重要的证书&#xff0c;薪资范围主要集中在4500-6000元之间。如果具…

Google RichHF-18K 文本到图像生成中的丰富人类反馈

每周跟踪AI热点新闻动向和震撼发展 想要探索生成式人工智能的前沿进展吗&#xff1f;订阅我们的简报&#xff0c;深入解析最新的技术突破、实际应用案例和未来的趋势。与全球数同行一同&#xff0c;从行业内部的深度分析和实用指南中受益。不要错过这个机会&#xff0c;成为AI领…

viscode-插件

vue组件生成&#xff1a; vue.json {"Print to console": {"prefix": "vue", "body": ["<!-- $1 -->","<template>","<div>","</div>","</template>&q…

MSPM0G3507——OPENMV给M0传数据(用数据包)互相通信(以循迹为例)

OPENMV端代码 # main.py -- put your code here! import pyb, sensor, image, math, time from pyb import UART import ustruct from image import SEARCH_DS, SEARCH_EX import time import sensor, displayuart UART(3, 115200, bits8, parityNone, stop1, timeout_char10…

2024上半年网络工程师考试《应用技术》试题一

阅读以下说明&#xff0c;回答问题。 【说明】 MPLS基于(1)进行转发&#xff0c;进行MPLS标签交换和报文转发的网络设备称为(2)&#xff0c;构成MPLS域(MPSDomain)。位于MPLS域边缘、连接其他网络的LSR称为(3),区域内部的LSR称为核心LSR(CoreLSR)IP报文进入MPLS网络时&#xf…

计算云服务2

第二章 裸金属服务器 什么是裸金属服务器(BMS) 裸金属服务器(Bare Metal Server&#xff0c;BMS)是一款兼具虚拟机弹性和物理机性能的计算类服务为用户以及相关企业提供专属的云上物理服务器&#xff0c;为核心数据库、关键应用系统、高性能计算、大数据等业务提供卓越的计算…

【Python】基于动态规划和K聚类的彩色图片压缩算法

引言 当想要压缩一张彩色图像时&#xff0c;彩色图像通常由数百万个颜色值组成&#xff0c;每个颜色值都由红、绿、蓝三个分量组成。因此&#xff0c;如果我们直接对图像的每个像素进行编码&#xff0c;会导致非常大的数据量。为了减少数据量&#xff0c;我们可以尝试减少颜色…

ComfyUI预处理器ControlNet简单介绍与使用(附件工作流)

简介 ControlNet 是一个很强的插件&#xff0c;提供了很多种图片的控制方式&#xff0c;有的可以控制画面的结构&#xff0c;有的可以控制人物的姿势&#xff0c;还有的可以控制图片的画风&#xff0c;这对于提高AI绘画的质量特别有用。接下来就演示几种热门常用的控制方式 1…

基于Hadoop平台的电信客服数据的处理与分析④项目实现:任务16:数据采集/消费/存储

任务描述 “数据生产”的程序启动后&#xff0c;会持续向callLog.csv文件中写入模拟的通话记录。接下来&#xff0c;我们需要将这些实时的数据通过Flume采集到Kafka集群中&#xff0c;然后提供给HBase消费。Flume&#xff1a;是Cloudera提供的一个高可用的&#xff0c;高可靠的…

期末考试结束,老师该如何私发成绩?

随着期末考试的落幕&#xff0c;校园里又恢复了往日的宁静。然而&#xff0c;对于老师们来说&#xff0c;这并不意味着工作的结束&#xff0c;相反&#xff0c;一系列繁琐的任务才刚刚开始。 成绩单的发放&#xff0c;就是其中一项让人头疼的工作。家长们焦急地等待着孩子的考试…

利用pg_rman进行备份与恢复操作

文章目录 pg_rman简介一、安装配置pg_rman二、创建表与用户三、备份与恢复 pg_rman简介 pg_rman 是 PostgreSQL 的在线备份和恢复工具。类似oracle 的 rman pg_rman 项目的目标是提供一种与 pg_dump 一样简单的在线备份和 PITR 方法。此外&#xff0c;它还为每个数据库集群维护…

kubernetes集群部署:node节点部署和cri-docker运行时安装(四)

安装前准备 同《kubernetes集群部署&#xff1a;环境准备及master节点部署&#xff08;二&#xff09;》 安装cri-docker 在 Kubernetes 1.20 版本之前&#xff0c;Docker 是 Kubernetes 默认的容器运行时。然而&#xff0c;Kubernetes 社区决定在 Kubernetes 1.20 及以后的…