(五)SpringBoot中的SpringSecurity

发布时间:2023-04-23 09:42:46

  SpringSecurity在SpringBoot中集成

  由于该项目采用了SpringBoot,因此将SpringSecurity集成到该项目中非常简单。只需介绍以下坐标:

(五)SpringBoot中的SpringSecurity_jar包

  然后启动项目,我们可以在控制台上看到这样的日志:

(五)SpringBoot中的SpringSecurity_jar包_02

  在引入SpringSecurity后,我们将随意编写一个Controler:

(五)SpringBoot中的SpringSecurity_jar包_03

  然后通过浏览器访问url,事故发生:

(五)SpringBoot中的SpringSecurity_jar包_04

(五)SpringBoot中的SpringSecurity_加载_05

  我们的请求是302到一个/login页面,但是我们的项目中没有这个login页面。别担心,这是SpringSecurity的默认行为。当你整合它时,他开始保护我们的项目。默认登录帐户为user,密码为前面日志中随机生成的字符串。

(五)SpringBoot中的SpringSecurity_spring_06

  登录成功后,我们就可以访问原来的controller了。太神奇了吗?我们只是介绍了一个jar包,它有如此强大的功能。你会考虑它是如何工作的。因此,在我们深入使用它之前,我认为最好了解它的工作原理,否则它会非常着迷。二、SpringBoot如何集成SpringSecurity

  因为一个成熟的框架必须涉及到很多知识,所以基本上不可能一次澄清整个框架的来龙去脉。我们只能通过编程经验慢慢探索框架的奥秘。为了了解SpringBoot是如何工作的,我们需要在了解之前熟悉至少相关的解释和配置。我在项目的基本配置

  landexiang:(1)SpringBoot构建基本后端应用22 赞同 · 0 评论文章

(五)SpringBoot中的SpringSecurity_jar包_07

  已经介绍过了。在这篇文章中,我只是简单地提到了@enableautoconfiguration,这个解释是用来帮助我们提供默认配置的,虽然没有说错,但介绍太简单了。让我们对这个解释有一点深入的了解,springsecurity是如何集成到springbot中的奥秘自然会被揭示。

  首先,让我们来看看这个注释的细节:

(五)SpringBoot中的SpringSecurity_jar包_08

  然后看@Import注释的内容:

(五)SpringBoot中的SpringSecurity_jar包_09

  这种注释本身没有什么特别之处,就是在类上运行时需要注释的注释,而且只提供一个属性。但是上面的注释可以为我们提供更多的帮助。注释大致意思是:@Import在xml配置文件中提供了和具有相同标签的能力。允许我们导入注释@configuration的类别,或实现Importselector或Importbeandefinitiondegistrar接口的实现类别。在spring4.2之前,我们甚至可以导入类似An的组件类notationConfigApplicationContext.register方法(这是一种动态注册配置方法,放置扩展链接)。

  使用 Java 配置进行 Spring bean 管理www.ibm.com/developerworks/cn/webservices/ws-springjava/index.html

  通过导读注释,我们可以了解到@Import注释可以引入多种类型,从而实现不同的功能。我们可以看到@enableautoconfiguration上的@Import引入了autoconfigutationimportselectortor.class的类别。找出这个类别的位置:

(五)SpringBoot中的SpringSecurity_spring_10

  它的顶部接口是

(五)SpringBoot中的SpringSecurity_jar包_11

  注意:Importselectors引入的配置类与普通@Import注释引入的配置类处理方法相同,但如果使用deferedimportselector,也可以在所有其他配置类别中直接发现或引入@configuration配置类处理后进行处理。我们可能不太明白这一点。我们发现deferedimportselector是autoconimportselector的直接父级接口。继续查看提到的deferedimportselector配置类的注释,大意是:这是一种特殊的ImportSelector,只有在所有@configuration的bean被处理后才能运行,即上述延迟运行。这种类型的selector在我们依靠@conditional引入某些配置时特别有用。这种类型的selector在我们依靠@conditional引入某些配置时特别有用。实现类也可以实现另一个ordered接口,然后通过使用@order注释来显示其优先级。还提供了一种getimportGroup方法,可以提供过滤或排序功能。

(五)SpringBoot中的SpringSecurity_jar包_12

  Autoconfigurationimportselector类继承了Orderd接口。

(五)SpringBoot中的SpringSecurity_spring_13

  此外,我们可以通过顶级接口ImportSelectors得出结论,该类提供的主要功能是SelectImports方法,因为这是顶级接口中唯一的方法。通过源码看到它返回到字符串数组,所以我们自然会想到,我们应该看看Autoconfigurationimportselector中selectimport方法作为实现类的具体实现:

(五)SpringBoot中的SpringSecurity_加载_14

  我们注意到了这一行:

(五)SpringBoot中的SpringSecurity_加载_15

  一般来说,像这样,参数只传输个别加载器的加载数据函数,通常有一些默认行为。它可以加载默认路径或指定类别,用我们的推断进入源代码:

(五)SpringBoot中的SpringSecurity_加载_16

  果然,在加载的指定路径下的配置文件。让我们来看看它的细节。此外,值得注意的是,如果在debug的过程中单纯按F7是无法进入的,则需要强制进入,shift + F7,我们可以看到Restartclaslader执行加载任务:

(五)SpringBoot中的SpringSecurity_spring_17

  debug显示其父加载器是系统加载器:

(五)SpringBoot中的SpringSecurity_jar包_18

  扩展加载器和引导加载器也高于系统加载器,因此tmp[0]是这两种加载器加载的内容

SpringSecurity_jar包_19'springBootSpringSecurity

  tmp[1]有点特别。它由URLClasspath加载。这种加载器将在lib中加载所有jar包

(五)SpringBoot中的SpringSecurity_加载_20

  然后在所有jar包的Classpath下搜索此配置文件。在

  landexiang:(3)Java资源文件及路径扫盲22 赞同 · 0 评论文章

(五)SpringBoot中的SpringSecurity_jar包_21

  本文介绍了类加载器的加载行为。

  让我们来看看jar包中有哪些配置文件。首先,直接show in AutoconfigurationMetadata类explorer,可追溯到其所在的jar包:

(五)SpringBoot中的SpringSecurity_spring_22

  打开这个jar包,看到Classpath//META-该配置文件确实存在于INF路径下:

(五)SpringBoot中的SpringSecurity_加载_23

  内容截图:

(五)SpringBoot中的SpringSecurity_加载_24

  spring-boot-devtools-2.1.1.RELEASE.这个文件也存在于jar包中

(五)SpringBoot中的SpringSecurity_jar包_25

(五)SpringBoot中的SpringSecurity_加载_26

  至于其他的,我们不需要注意。debug显示在我的项目中,从这些配置文件中加载了690个键对,并构建了一个Propertiesautoconfigurationmetadata返回。

(五)SpringBoot中的SpringSecurity_spring_27

(五)SpringBoot中的SpringSecurity_spring_28

  获取数据后,必须处理这些配置数据:

(五)SpringBoot中的SpringSecurity_spring_29

  Annotationmeta是Spring提供的注解元数据的包装类别,可以更好地管理注解。getattribute意味着取出注解的属性值,而当前启动类的注解是@SpringBootApplication,前面已经说过他继承了@EnableAutoConfiguration,所以这里取出的属性是@Enableautoconfiguration

(五)SpringBoot中的SpringSecurity_加载_30

  也就是说,exclude和excludename这两个数组值

(五)SpringBoot中的SpringSecurity_jar包_31

  结果和我们预期的一样。

(五)SpringBoot中的SpringSecurity_加载_32

  接下来的事情更有趣,

(五)SpringBoot中的SpringSecurity_jar包_33

  注释的意思是:通过默认的SpringFactoriesloder.getSpringFactoriesLoaderFactoryClass()方法返回一些需要使用的Classname集合。

  我们可以通过注释获得两个信息:

  1、该函数的默认行为可能是加载固定路径或加载固定类

  2、返回值是Listt,Classnamee元素是Clasname

  用猜测看源码

(五)SpringBoot中的SpringSecurity_加载_34

  固定的类

(五)SpringBoot中的SpringSecurity_加载_35

  主要加载逻辑如下:

(五)SpringBoot中的SpringSecurity_jar包_36

  从结构上看,这是一个基本的缓存结构,有的返回,没有的初始化。从代码上看,FACTORIES是通过类加载器加载的RESOURCE_LOCATION路径下的资源

(五)SpringBoot中的SpringSecurity_jar包_37

  我们可以找到一个配置文件来打开内容:

(五)SpringBoot中的SpringSecurity_加载_38

  也是一个个键值对,键是Classname。所以串起来我们就知道这个getcandidateconfigurations的意图了。在Classpath路径下加载所有jar包中的META-INF/spring.factories文件中键org.springframework.boot.autoconfigure.EnableAutoConfiguration值。

(五)SpringBoot中的SpringSecurity_加载_39

  之后是对这些数据的处理,有去重操作。去除在@enableautoconfiguration中配置exclude的操作,这是从注释属性中提取的内容的功能。然后是过滤操作。当我们看到这两个参数时,我们心里可能会有一些猜测。

(五)SpringBoot中的SpringSecurity_spring_40

  这两个参数分别是:

  configurations:从META-INF/spring.从factories文件中取出的classname集合

  autoConfigutationMetadata: 从META-INF/spring-autoconfigure-metadata.properties文件中加载的键值集合

(五)SpringBoot中的SpringSecurity_spring_41

(五)SpringBoot中的SpringSecurity_spring_42

(五)SpringBoot中的SpringSecurity_jar包_43

  我们已经看到了这里所有的代码。所以很容易看出,getautoconfigurationimportfilters实际上是从claspath路径下的META-INF/spring.factories文件中加载了Autoconfigutationimportfilter作为键的所有配置,并在实例化后返回。根据@ordered排序,我们也可以看到一个排序操作。spring.factories文件中的配置和debug显示的结果如下:

(五)SpringBoot中的SpringSecurity_jar包_44

(五)SpringBoot中的SpringSecurity_加载_45

  Springboot配置必须是@ConditionalOnClass、@ConditionalOnBean、@conditionalonwenaplication并不陌生,条件注入。因此,这些class实际上是根据条件注入过滤的。 选择是否进行实例Bean操作。

  然后根据Aware接口对实例化完成的三个对象进行相应的赋值操作,Aware系统已经在上一节进行了分析。可见SpringBoot其实就是这样。。

(五)SpringBoot中的SpringSecurity_spring_46

  在我的项目中,只剩下36个类,箭头所指的类似乎离我们要追求的真相不远了。

(五)SpringBoot中的SpringSecurity_加载_47

  我们以后不需要介绍。这36个类别注册为bean并加载到Spring的上下文中,所以我们只需要直接查看我们需要的类别。三、SecurityAutoConfiguration

  1、基本内容

(五)SpringBoot中的SpringSecurity_spring_48

  显然,这是一个配置类,经过上述自动化加载后,spring将作为配置类进行分析。他还介绍了另外三个配置类别。

(五)SpringBoot中的SpringSecurity_spring_49

(五)SpringBoot中的SpringSecurity_加载_50

(五)SpringBoot中的SpringSecurity_加载_51

  稍微介绍一下条件注释:

  @ConditionalOnBean(只有在当前上下文中有一个对象时,才会实例化一个Bean)

  @ConditionalOnClass(只有当class位于类路径上时,才会实例化一个bean)

  @ConditionalOnExpression(当表达式为true时,将实例化为bean)

  @ConditionalOnMissingBean(只有在当前上下文中没有对象时,才会实例化一个Bean)

  @ConditionalOnMissingClass(当class类路径不存在时,就会实例化一个bean)

  @ConditionalOnNotWebApplication(不是web应用)

  @ConditionalonProperty是指application.yml中配置的属性是true吗?

  还有个@EnableConfigurationProperties(SecurityProperties.class)不是条件注释,而是引用了SecurityPropertiess。.简单来说,class的配置类就是使用@configurationProperties注释。

(五)SpringBoot中的SpringSecurity_spring_52

  @ConfigurationProperties有两个功能:未注释的类生成bean,spring配置文件中的内容根据指定的前缀和属性名加载到bean中。以我的yml配置文件为例:

(五)SpringBoot中的SpringSecurity_加载_53

  层次关系和字段名正好一一对应:

(五)SpringBoot中的SpringSecurity_jar包_54

  2、DefaultConfigAdapter

  在Springbootwebsecurityconfig类中,我们发现了另一个配置类,DefaultConfigAdapter:

(五)SpringBoot中的SpringSecurity_加载_55

  但是,他们的父亲没有看到注释,说明他们需要注册为bean注释,所以这个configuration应该没用。

(五)SpringBoot中的SpringSecurity_spring_56

  3、@EnableWebSecurity

(五)SpringBoot中的SpringSecurity_jar包_57

  我们在websecurityenablerconfiguration类上发现了这个注释。具体内容如下:

(五)SpringBoot中的SpringSecurity_spring_58

  可见这个注释又引入了另外三个类别。。但这三类中只有一类是配置类,即WebSecurityConfiguration.class:

(五)SpringBoot中的SpringSecurity_jar包_59

  部分截图

  终于看到了bean的相关配置,但是有几个bean使用了@dependson注释,用来控制bean的加载顺序,所以在这个类中找到这个特定类型的bean。:

(五)SpringBoot中的SpringSecurity_加载_60

  嘿,这个名字,springSecurityFilterChain,有点熟悉吗?还记得我们在分析Springweb中的Filter系统时,在web上注册的.SpringSecurity的入口Filter是SpringSecurityFilterchain,SpringSecuriterchain是SpringSecurity自动加载到Spring的上下文,因此可以从bean工厂找到这个filterbean。

  landexiang:(4)SpringWebfilter系统简介18 赞同 · 4 评论文章

(五)SpringBoot中的SpringSecurity_加载_61

  4、springSecurityFilterChain

  现在我们终于可以把SpringSecurity和SpringSecurity的配置稍微联系起来了。我们来看看这个bean的加载逻辑,做了什么。

(五)SpringBoot中的SpringSecurity_spring_62

  通过debug,直接调用websecurity的build方法:

(五)SpringBoot中的SpringSecurity_jar包_63

  继续debug,看看他做了什么。

(五)SpringBoot中的SpringSecurity_加载_64

  O泛型作为返回值,必须是Filter类型,即dobuild返回Filter对象:

(五)SpringBoot中的SpringSecurity_jar包_65

  或者先看注释,大意是:使用以下步骤模板,通过注册的Securityconfigurer完成build工作。1、beforeinit是留给子类定义的hook钩子函数。2、执行所有有效的SecurityConfigurerinitinittitin(SecurityBuilder)方法。3、beforeconfigure也是留给子类的钩子函数。4、performbuild是真正的返回结果创建函数。

  从注释来看,init方法是SpringSecurity的一些默认配置,暂时不用,因为我们的主题是SpringBoot和SpringSecurity,所以直接看performBuild方法。

(五)SpringBoot中的SpringSecurity_加载_66

  ignorequests用于配置忽略某些请求,即不需要通过SpringSecurity的拦截验证。

(五)SpringBoot中的SpringSecurity_加载_67

(五)SpringBoot中的SpringSecurity_加载_68

  securityfilterchainbuilder是httpsecurity的对象。通过这个对象的build方法,可以创建一个爱你的securityfilterchain:

(五)SpringBoot中的SpringSecurity_spring_69

  debug显示默认requstMatcherany request,也就是说,拦截所有请求。默认有15个filters,SpringSecurity应该为我们提供SpringSecurity的基本功能:

(五)SpringBoot中的SpringSecurity_spring_70

  FilterchainProxy通过上述创建的Filter链构建,即该链的代理:

SpringSecurity_jar包_71'springBootSpringSecurity

  最后,设置了Filterserityinterceptor

(五)SpringBoot中的SpringSecurity_加载_72

  前面的FilterChainProxy创建的结果是:

(五)SpringBoot中的SpringSecurity_加载_73

  这个filterchainProxy的beannname是springsecurityfilterchain,即一个包含许多filter的filter对象。

  综上所述,SpringSecurity提供的默认配置是由SpringBoot加载的,其中生成了为SpringSecuriterChain的Filter类型的bean。他默认拦截所有路径,内部包含15个默认filter。为外界提供SpringSecurity的能力。三、SpringSecurityFilter处理请求:

  在最后一篇文章中,我们已经知道了dofilterproxy调用springsecuriterchain的dofilter方法,现在我们已经找到了springsecuriterchain的bean,让我们看看他的dofilter方法做了什么。

  通过源码,我们可以看到SpringSecurityFilterchain的实际类型实际上是FilterchainProxy

(五)SpringBoot中的SpringSecurity_jar包_74

  让我们来看看这类dofilter方法:

(五)SpringBoot中的SpringSecurity_spring_75

  启动项目,随意输入请求,

(五)SpringBoot中的SpringSecurity_spring_76

(五)SpringBoot中的SpringSecurity_加载_77

(五)SpringBoot中的SpringSecurity_jar包_78

  先给request设置一个值为true的属性,然后执行dofilterinternal函数:

(五)SpringBoot中的SpringSecurity_spring_79

(五)SpringBoot中的SpringSecurity_jar包_80

(五)SpringBoot中的SpringSecurity_加载_81

  从代码的角度来看,是否处理request取决于requestmatcher的对象是否成功。如果filters为空,则表示springsecurity不需要处理,并直接交给过滤器链的下一个链进行处理

(五)SpriSpringSecurity_jar包_82

  如需SpringSecurity处理,则构建VirtualFilterchain对象进行处理:

(五)SpringBoot中的SpringSecurity_spring_83

(五)SpringBoot中的SpringSecurity_spring_84

  处理逻辑也很简单,依次调用filterchain中filter的dofilter方法,调用delegatingfilterproxy传来的filterchain(即originchain)的dofilter方法。所以要想知道SpringSecurity默认为我们做了什么,还是要看看这15个默认Filter有什么特点,做了什么工作:四、SpringSecurity提供的Filters默认分析

  通过debug,我们可以看到SpringSecurity提供了15个默认Filter。

(五)SpringBoot中的SpringSecurity_jar包_85

  而且从他的调用逻辑来看,有顺序关系。但是我们看完这么多Filter都太累了。所以选择一个有趣的,排名第五的UsernamePaswordAuthenticationFilter。:

(五)SpringBoot中的SpringSecurity_jar包_86

  UsernamePaswordAuthenticationfilter继承Abstractatinticationpronprocesingfilterter

(五)SpringBoot中的SpringSecurity_spring_87

  dofilter方法是在父类中实现的:

(五)SpringBoot中的SpringSecurity_加载_88

(五)SpringBoot中的SpringSecurity_spring_89

  逻辑首先是要求信息匹配,

(五)SpringBoot中的SpringSecurity_jar包_90

  只接受POST类型的请求

(五)SpringBoot中的SpringSecurity_加载_91

  只拦截url是/loginurl

(五)SpringBoot中的SpringSecurity_spring_92

  所以这个UsernamePaswordauthenticationfilter只拦截/login的post请求。

  然后是试验验证,

(五)SpringBoot中的SpringSecurity_加载_93

  可见用户名和密码都是从request中取出的参数,

SpringSecurity_jar包_94'springBootSpringSecurity

  参数名分别为username和pasword

(五)SpringBoot中的SpringSecurity_spring_95

  然后将用户名和密码封装成usernamePaswordauthenticationticaticaticaten对象,并将其作为参数交给authenticaticaticaticaticaten方法。还记得之前的debug吗?这种authenticationmanager的类型是Providermanager:

(五)SpringBoot中的SpringSecurity_加载_96

  暂且不管验证逻辑,等到谈论SpringSecurity源代码时再谈。让我们先关注这个过程。

(五)SpringBoot中的SpringSecurity_spring_97

  下面的逻辑也很简单。如果验证失败,则调用unsucesfulauthentication,如果验证成功,则调用sucesfulauthentication。

(五)SpringBoot中的SpringSecurity_spring_98

(五)SpringBoot中的SpringSecurity_加载_99

  但具体处理是交给这两个handler进行的。

(五)SpringBoot中的SpringSecurity_spring_100

  通过简单的源码分析,我们可以知道默认登录的验证是交给ProviderManager的.authenticate完成。

  通过简单的分析,我们已经清楚SpringSecurity是如何访问web项目的。下面总结一下:

  在web.在xml中注册了一种叫做springSecurityFiterchain的Filter,类型为delegatingFilterProxy,他将在dofilter方法中将filterchian传递给spring上下文中一种叫做springspriterchin的filter类型(实际上是filterchainproxy)的beandofilter方法。SpringSecurityfilterchain是由Springbot@enableautoconfiguration注释加载的。默认加载的类别是项目所有jar包Classpath/META-INF/spring-autoconfigure-metadata.properties、ClassPath/META-INF/spring.factories 由这两个配置文件和这些配置类别的注释条件共同决定。

  其中有SpringSecurity的配置类。在SpringSecurity的配置类别中,默认生成了一个名为SpringSecurityFitlerchain的bean。SpringSecurity的配置类主要存在于@enablewebsecurity注释引入的websecurityConfigurition配置类中。

  现在我们对SpringSecurity的工作基本原理有了粗浅的了解。下一节,我们将分析UsernamePaswordauthenticationfiter的详细工作流程和SpringSecurity默认配置的源代码。然后看看如何自定义配置覆盖SpringSecurity的默认配置,并重用他提供的Filter来完成我们自己的登录流程。

上一篇 掌握云服务新趋势!精解多租户架构,开创企业数字化新纪元!
下一篇 关闭防火墙导致docker容器启动异常

文章素材均来源于网络,如有侵权,请联系管理员删除。

标签: Java教程Java基础Java编程技巧面试题Java面试题