当前位置: 首页 > news >正文

SpringBoot Security安全认证框架初始化流程认证流程之源码分析

SpringBoot Security安全认证框架初始化流程&认证流程之源码分析

以RuoYi-Vue前后端分离版本为例分析SpringBoot Security安全认证框架初始化流程&认证流程的源码分析

目录

  • SpringBoot Security安全认证框架初始化流程&认证流程之源码分析
  • 一、SpringBoot Security安全认证框架初始化流程
    • 1、引入springboot-security依赖
    • 2、EnableWebSecurity注解
    • 3、WebSecurityConfiguration
      • 3.1、setFilterChainProxySecurityConfigurer方法
      • 3.2、springSecurityFilterChain方法
    • 4、自定义安全配置类
  • 二、SpringBoot Security认证流程
    • 1、在用户登录认证类中自动注入AuthenticationManager对象
    • 2、调用Spring Security安全认证方法
  • 三、SpringBoot启动源码分析

一、SpringBoot Security安全认证框架初始化流程

在这里插入图片描述

《SpringBoot Security安全认证框架初始化流程梳理图》

1、引入springboot-security依赖

<!-- spring security 安全认证 -->
<dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-security</artifactId>
</dependency>

2、EnableWebSecurity注解

org.springframework.security.config.annotation.web.configureation.EnableWebSecurity

  • 添加该注解到@Configuration的类上,应用程序便可以使用自定义的WebSecurityConfigurer或拓展自WebSecurityConfigurerAdapter的配置类来装配Spring Security框架。

EnableWebSecurity.java 源码

package org.springframework.security.config.annotation.web.configuration;import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.security.config.annotation.authentication.configuration.EnableGlobalAuthentication;
import org.springframework.security.config.annotation.web.WebSecurityConfigurer;@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
@Import({ WebSecurityConfiguration.class, SpringWebMvcImportSelector.class, OAuth2ImportSelector.class,HttpSecurityConfiguration.class })
@EnableGlobalAuthentication
@Configuration
public @interface EnableWebSecurity {/*** Controls debugging support for Spring Security. Default is false.* @return if true, enables debug support with Spring Security*/boolean debug() default false;}

说明:


在此注解接口定义中引入了 WebSecurityConfiguration

3、WebSecurityConfiguration

3.1、setFilterChainProxySecurityConfigurer方法

重点:
1、将自定义的安全配置类对象注入到Spring容器中;
2、构建WebSecurity对象

说明:
1、获取安全配置,通过@value的方式实现了AutowiredWebSecurityConfigurersIgnoreParents.getWebSecurityConfigurers();
2、获取类型为WebSecurityConfigurer类及其子类匹配的bean,包括WebSecurityConfigurerAdapter、继承WebSecurityConfigurerAdapter的自定义安全配置类


1)、通过@value(“#{@autowiredWebSecurityConfigurersIgnoreParents.getWebSecurityConfigurers()}”)获取安全配置
2)、调用org.springframework.security.config.annotation.web.configuration.AutowiredWebSecurityConfigurersIgnoreParents.getWebSecurityConfigurers()

@Autowired(required = false)public void setFilterChainProxySecurityConfigurer(ObjectPostProcessor<Object> objectPostProcessor,@Value("#{@autowiredWebSecurityConfigurersIgnoreParents.getWebSecurityConfigurers()}") List<SecurityConfigurer<Filter, WebSecurity>> webSecurityConfigurers)throws Exception {this.webSecurity = objectPostProcessor.postProcess(new WebSecurity(objectPostProcessor));if (this.debugEnabled != null) {this.webSecurity.debug(this.debugEnabled);}webSecurityConfigurers.sort(AnnotationAwareOrderComparator.INSTANCE);Integer previousOrder = null;Object previousConfig = null;for (SecurityConfigurer<Filter, WebSecurity> config : webSecurityConfigurers) {Integer order = AnnotationAwareOrderComparator.lookupOrder(config);if (previousOrder != null && previousOrder.equals(order)) {throw new IllegalStateException("@Order on WebSecurityConfigurers must be unique. Order of " + order+ " was already used on " + previousConfig + ", so it cannot be used on " + config + " too.");}previousOrder = order;previousConfig = config;}for (SecurityConfigurer<Filter, WebSecurity> webSecurityConfigurer : webSecurityConfigurers) {this.webSecurity.apply(webSecurityConfigurer);}this.webSecurityConfigurers = webSecurityConfigurers;}

3.2、springSecurityFilterChain方法

说明:


1、通过@Bean将springSecurityFilterChain()方法构建的Filter实例对象按名称为springSecurityFilterChain的Bean注入到Spring容器中
2、WebSecurity.build方法会启动对象的配置,重点是: 【可以调用到自定义安全配置类的配置方法】实现自定义配置认证退出处理类、不用认证url等SpringBoot Security安全配置

@Bean(name = AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME)
public Filter springSecurityFilterChain() throws Exception {boolean hasConfigurers = this.webSecurityConfigurers != null && !this.webSecurityConfigurers.isEmpty();boolean hasFilterChain = !this.securityFilterChains.isEmpty();Assert.state(!(hasConfigurers && hasFilterChain),"Found WebSecurityConfigurerAdapter as well as SecurityFilterChain. Please select just one.");if (!hasConfigurers && !hasFilterChain) {WebSecurityConfigurerAdapter adapter = this.objectObjectPostProcessor.postProcess(new WebSecurityConfigurerAdapter() {});this.webSecurity.apply(adapter);}for (SecurityFilterChain securityFilterChain : this.securityFilterChains) {this.webSecurity.addSecurityFilterChainBuilder(() -> securityFilterChain);for (Filter filter : securityFilterChain.getFilters()) {if (filter instanceof FilterSecurityInterceptor) {this.webSecurity.securityInterceptor((FilterSecurityInterceptor) filter);break;}}}for (WebSecurityCustomizer customizer : this.webSecurityCustomizers) {customizer.customize(this.webSecurity);}return this.webSecurity.build();
}

4、自定义安全配置类

自定义安全配置类继承WebSecurityConfigurerAdapter,以对象名为authenticationManager的bean将AuthenticationManager对象注入到Spring容器中

在这里插入图片描述

《authenticationManager的bean对象注入流程源码分析图》

说明:


1、以@Bean的方式将AuthenticationManager的Bean以Id="authenticationManager"注入到Spring容器中;
2、调用父类WebSecurityConfigurerAdapter的authenticationManagerBean()方法


重点: 通过authenticationManagerBean()方法实现了将ProviderManager对象做为AuthenticationManager的实例对象,参照 第二章节->2、调用Spring Security安全认证方法中的《将ProviderManager对象做为authenticationManager的bean对象流程源码分析图》

自定义安全配置类源码

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.logout.LogoutFilter;
import org.springframework.web.filter.CorsFilter;
import cn.edu.tit.ipaddress.ms.framework.config.properties.PermitAllUrlProperties;
import cn.edu.tit.ipaddress.ms.framework.security.filter.JwtAuthenticationTokenFilter;
import cn.edu.tit.ipaddress.ms.framework.security.handle.AuthenticationEntryPointImpl;
import cn.edu.tit.ipaddress.ms.framework.security.handle.LogoutSuccessHandlerImpl;/*** spring security配置* * @author ruoyi*/
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter
{/*** 自定义用户认证逻辑*/@Autowiredprivate UserDetailsService userDetailsService;/*** 认证失败处理类*/@Autowiredprivate AuthenticationEntryPointImpl unauthorizedHandler;/*** 退出处理类*/@Autowiredprivate LogoutSuccessHandlerImpl logoutSuccessHandler;/*** token认证过滤器*/@Autowiredprivate JwtAuthenticationTokenFilter authenticationTokenFilter;/*** 跨域过滤器*/@Autowiredprivate CorsFilter corsFilter;/*** 允许匿名访问的地址*/@Autowiredprivate PermitAllUrlProperties permitAllUrl;/*** 解决 无法直接注入 AuthenticationManager** @return* @throws Exception*/@Bean@Overridepublic AuthenticationManager authenticationManagerBean() throws Exception{return super.authenticationManagerBean();}/*** anyRequest          |   匹配所有请求路径* access              |   SpringEl表达式结果为true时可以访问* anonymous           |   匿名可以访问* denyAll             |   用户不能访问* fullyAuthenticated  |   用户完全认证可以访问(非remember-me下自动登录)* hasAnyAuthority     |   如果有参数,参数表示权限,则其中任何一个权限可以访问* hasAnyRole          |   如果有参数,参数表示角色,则其中任何一个角色可以访问* hasAuthority        |   如果有参数,参数表示权限,则其权限可以访问* hasIpAddress        |   如果有参数,参数表示IP地址,如果用户IP和参数匹配,则可以访问* hasRole             |   如果有参数,参数表示角色,则其角色可以访问* permitAll           |   用户可以任意访问* rememberMe          |   允许通过remember-me登录的用户访问* authenticated       |   用户登录后可访问*/@Overrideprotected void configure(HttpSecurity httpSecurity) throws Exception{// 注解标记允许匿名访问的urlExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry registry = httpSecurity.authorizeRequests();permitAllUrl.getUrls().forEach(url -> registry.antMatchers(url).permitAll());httpSecurity// CSRF禁用,因为不使用session.csrf().disable()// 禁用HTTP响应标头.headers().cacheControl().disable().and()// 认证失败处理类.exceptionHandling().authenticationEntryPoint(unauthorizedHandler).and()// 基于token,所以不需要session.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()// 过滤请求.authorizeRequests()// 对于登录login 注册register 验证码captchaImage 允许匿名访问.antMatchers("/login","/loginWeixin","/register", "/captchaImage").permitAll()// 静态资源,可匿名访问.antMatchers(HttpMethod.GET, "/", "/*.html", "/**/*.html", "/**/*.css", "/**/*.js", "/profile/**").permitAll().antMatchers("/swagger-ui.html", "/swagger-resources/**", "/webjars/**", "/*/api-docs", "/druid/**").permitAll()// 除上面外的所有请求全部需要鉴权认证.anyRequest().authenticated().and().headers().frameOptions().disable();// 添加Logout filterhttpSecurity.logout().logoutUrl("/logout").logoutSuccessHandler(logoutSuccessHandler);// 添加JWT filterhttpSecurity.addFilterBefore(authenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);// 添加CORS filterhttpSecurity.addFilterBefore(corsFilter, JwtAuthenticationTokenFilter.class);httpSecurity.addFilterBefore(corsFilter, LogoutFilter.class);}/*** 强散列哈希加密实现*/@Beanpublic BCryptPasswordEncoder bCryptPasswordEncoder(){return new BCryptPasswordEncoder();}/*** 身份认证接口*/@Overrideprotected void configure(AuthenticationManagerBuilder auth) throws Exception{auth.userDetailsService(userDetailsService).passwordEncoder(bCryptPasswordEncoder());}
}

二、SpringBoot Security认证流程

1、在用户登录认证类中自动注入AuthenticationManager对象

自动注入AuthenticationManager对象

@Resource
private AuthenticationManager authenticationManager;

@Resource注解-说明:


一、@Resource和@Autowired异同
@Resoutce注解的功能和@Autowired相似的,可以互相替换,一般情况是可以正常运行的,由> @Resource标注的属性也会进行自动装配

二、二者区别:
1.提供者不同:
@AutoWired是Spring提供的
@Resource是由Java提供的


2.注入规则不同:
原则上@Autowired注入规则为“byType”(通过类型注入)
原则上@Resource注入规则为“byName”(通过名称注入)这里的名称就是对象的id


3.匹配规则不同
@Auotowired是先检查类型,如果有类型匹配直接匹配,只通过类型不能匹配,在通过id;
@Resource是先匹配id,如果有id匹配,直接成功;如果没有id匹配,在进行类型匹配;

2、调用Spring Security安全认证方法

关键代码

// 用户名、密码构建UsernamePasswordAuthenticationToken对象
UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(username, password);AuthenticationContextHolder.setContext(authenticationToken);
// 调用认证方法,验证用户名和密码
Authentication authentication = authenticationManager.authenticate(authenticationToken);

在这里插入图片描述

《将ProviderManager对象做为authenticationManager的bean对象流程源码分析图》

说明


验证用户名和密码,通过调用认证方法后,通过上图所示最终是调用了ProviderManager.authenticate()方法

在这里插入图片描述

《SpringBoot Security - 登录认证流程源码分析图》

说明


1、ProviderManager.authenticate()方法中通过getProviders()获取认证Provider实现类;
2、Provider实现类 - DaoAuthenticationProvider实现类,并继承AbstractUserDetailsAuthenticationProvider;

三、SpringBoot启动源码分析

下图为SpringBoot启动源码分析图,与SpringBoot Security没有关系,如果对SpringBoot启动熟悉的话可以跳过此章节内容。

在这里插入图片描述

《SpringBoot启动源码分析图》
http://www.lryc.cn/news/295198.html

相关文章:

  • 2024美赛预测算法 | 回归预测 | Matlab基于RIME-LSSVM霜冰算法优化最小二乘支持向量机的数据多输入单输出回归预测
  • test1
  • 远程主机可能不符合 glibc 和 libstdc++ Vs Code 服务器的先决条件
  • 备战蓝桥杯---数据结构与STL应用(进阶2)
  • SpringBoot:多环境配置
  • input框中添加一个 X(关闭/清空按钮)
  • Unity3d Shader篇(三)— 片元半兰伯特着色器解析
  • 【vue3学习P5-P10】vue3语法;vue响应式实现
  • 相机图像质量研究(3)图像质量测试介绍
  • PaddleDetection学习5——使用Paddle-Lite在 Android 上实现实时的人脸检测(C++)
  • 全套电气自动化样例图纸分享,使用SuperWorks自动化版免费设计软件!
  • 带你实现用自己域名打开Tomcat
  • python coding with ChatGPT 打卡第18天| 二叉树:从中序与后序遍历序列构造二叉树、最大二叉树
  • java基础训练题(1)
  • 【自定义序列化器】⭐️通过继承JsonSerializer和实现WebMvcConfigurer类完成自定义序列化
  • 闲聊电脑(5)装个 Windows(一)
  • 力扣(leetcode)第414题第三大的数(Python)
  • 使用wda框架实现IOS自动化测试详解
  • LeetCode--代码详解 2.两数相加
  • 【Django开发】美多商城项目第3篇:用户注册和图片验证码开发(附代码,文档已分享)
  • 代码随想录算法训练营DAY10 | 栈与队列 (1)
  • flinkjar开发 自定义函数
  • Golang 学习(一)基础知识
  • C++学习:string的了解
  • Webpack源码浅析
  • Hadoop:HDFS学习巩固——基础习题及编程实战
  • SASS 官方文档速通
  • 《动手学深度学习(PyTorch版)》笔记7.4
  • 关于自动驾驶概念的学习和一些理解
  • C++ dfs搜索枚举(四十八)【第八篇】