1.概述

  • spring security有参考的中文翻译文档https://springcloud.cc/spring-security-zhcn.html
  • 在学习spring security的时候,参考的书籍并不是很多,线上的技术博文也是没有系统的全面的介绍,不得不去参考源代码,发费了大量时间和精力,而我试图也通过一系列的文章,能结合自己的学习经历,循序渐进的表达清楚自己所理解到的点。
  • 所有的文章都是对源代码的解读,最后会给出一个小小的demo。
  • 选用的 spring boot版本1.4.3.RELEASE,spring cloud版本Camden.SR4(后面有结合网关zuul做oauth2 认证授权介绍)。版本非spring 最新版本,选用的是平时使用最多版本。
  • 文章是作为学习笔记性质为目的.当然如果文章能帮到有需要的朋友自然是特别开心和幸福的事情。有理解错误和不到位的点也希望各位指出,一起学习一起成长,一直没有都没敢写公开技术文章,第一本人水平有限,第二是不希望因为自己的错误给别人造成误导。

2.启动

2.1 简单的开始

从文档中可知,spring引入我们的项目只需要分为两步

  • maven引入需要的包,spring boot中引入的spring security版本为4.1.4
 <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
  • 配置spring security(spring security官方文档给出的例子,后面简称例子1)
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
<span class="hljs-meta"><span class="hljs-meta">@Autowired</span></span>
<span class="hljs-function"><span class="hljs-keyword"><span class="hljs-function"><span class="hljs-keyword">public</span></span></span><span class="hljs-function"> </span><span class="hljs-keyword"><span class="hljs-function"><span class="hljs-keyword">void</span></span></span><span class="hljs-function"> </span><span class="hljs-title"><span class="hljs-function"><span class="hljs-title">configureGlobal</span></span></span><span class="hljs-params"><span class="hljs-function"><span class="hljs-params">(AuthenticationManagerBuilder auth)</span></span></span><span class="hljs-function"> </span><span class="hljs-keyword"><span class="hljs-function"><span class="hljs-keyword">throws</span></span></span><span class="hljs-function"> Exception </span></span>{
auth
.inMemoryAuthentication()
.withUser(<span class="hljs-string"><span class="hljs-string">"user"</span></span>).password(<span class="hljs-string"><span class="hljs-string">"password"</span></span>).roles(<span class="hljs-string"><span class="hljs-string">"USER"</span></span>);
}

}

2.2 简单后面的繁琐

我们洁简的应用spring security到我们的项目,然后却开启了非常强大的功能,上面的例子,在内存中配置了一个用户名为user,密码为password,并且拥有USER角色的用户。我们还是要探究一下,spring security到底为我们做了一些什么样的工作。

我们的入手点只有两个,@EnableWebSecurity注解和WebSecurityConfigurerAdapter这个适配器类。

2.2.1 @EnableWebSecurity 注解

注解源代码

@Retention(value = java.lang.annotation.RetentionPolicy.RUNTIME)
@Target(value = { java.lang.annotation.ElementType.TYPE })
@Documented
@Import({ WebSecurityConfiguration.class,
SpringWebMvcImportSelector.class,
OAuth2ImportSelector.class })
@EnableGlobalAuthentication
@Configuration
public @interface EnableWebSecurity {
boolean debug() default false;

此处还是有必要简单翻译一下官方对于类的注释,以便于更加清楚的理解注解的作用

注释中提到两个很重要的点,以及一个配置示例,

  • 第一个点:@EnableWebSecurity配置到拥有注解 @Configuration的类上,就可以获取到spring security的支持.
  • 第二个点: WebSecurityConfigurer的子类可以扩展spring security的应用

由此可知@EnableWebSecurity使我们拥有spring security的能力。WebSecurityConfigurer 使我们能根据业务扩展我们的应用,而WebSecurityConfigurerAdapterWebSecurityConfigurer 的一个适配器,必然也是做了很多默认的工作。后面我们会一一说到。

从以上可以稍微总结一下我们下一步需要探究的问题,

  • WebSecurityConfigurerAdapter到底为我们做了什么工作.
  • 上面注解的源代码中Import了一个很重要的配置类WebSecurityConfiguration怎样组件我们的过滤器(或者说过滤器链)

2.2.2 spring security创建流程

spring security加载流程
  • 如果我们忽略掉细节,只看最重要的步骤,大概如此.下面我们对每一个步骤来做相应的源代码解释

WebSecurityConfiguration中的 setFilterChainProxySecurityConfigurer()方法

@Autowired(required = false)
public void setFilterChainProxySecurityConfigurer(
ObjectPostProcessor<Object> objectPostProcessor,
//T1 使用@Value获取到配置信息
@Value("#{@autowiredWebSecurityConfigurersIgnoreParents.getWebSecurityConfigurers()}") List<SecurityConfigurer<Filter, WebSecurity>> webSecurityConfigurers)
throws Exception {
     <span class="hljs-comment"><span class="hljs-comment">//T2 创建一个webSecurity 对象</span></span>
webSecurity = objectPostProcessor
.postProcess(<span class="hljs-keyword"><span class="hljs-keyword">new</span></span> WebSecurity(objectPostProcessor));
<span class="hljs-keyword"><span class="hljs-keyword">if</span></span> (debugEnabled != <span class="hljs-keyword"><span class="hljs-keyword">null</span></span>) {
webSecurity.debug(debugEnabled);
} <span class="hljs-comment"><span class="hljs-comment">//T3对configures进行排序</span></span>
Collections.sort(webSecurityConfigurers, AnnotationAwareOrderComparator.INSTANCE); <span class="hljs-comment"><span class="hljs-comment">//T4对Order进行比较是否有相同的,由于前面进行了排序,只要比较前后有相同的就可以</span></span>
Integer previousOrder = <span class="hljs-keyword"><span class="hljs-keyword">null</span></span>;
Object previousConfig = <span class="hljs-keyword"><span class="hljs-keyword">null</span></span>;
<span class="hljs-keyword"><span class="hljs-keyword">for</span></span> (SecurityConfigurer&lt;Filter, WebSecurity&gt; config : webSecurityConfigurers) {
Integer order = AnnotationAwareOrderComparator.lookupOrder(config);
<span class="hljs-keyword"><span class="hljs-keyword">if</span></span> (previousOrder != <span class="hljs-keyword"><span class="hljs-keyword">null</span></span> &amp;&amp; previousOrder.equals(order)) {
<span class="hljs-keyword"><span class="hljs-keyword">throw</span></span> <span class="hljs-keyword"><span class="hljs-keyword">new</span></span> IllegalStateException(
<span class="hljs-string"><span class="hljs-string">"@Order on WebSecurityConfigurers must be unique. Order of "</span></span>
+ order + <span class="hljs-string"><span class="hljs-string">" was already used on "</span></span> + previousConfig + <span class="hljs-string"><span class="hljs-string">", so it cannot be used on "</span></span>
+ config + <span class="hljs-string"><span class="hljs-string">" too."</span></span>);
}
previousOrder = order;
previousConfig = config;
}
<span class="hljs-keyword"><span class="hljs-keyword">for</span></span> (SecurityConfigurer&lt;Filter, WebSecurity&gt; webSecurityConfigurer : webSecurityConfigurers) {
<span class="hljs-comment"><span class="hljs-comment">//T5将配置信息配置到webSecurity中</span></span>
webSecurity.apply(webSecurityConfigurer);
}
<span class="hljs-keyword"><span class="hljs-keyword">this</span></span>.webSecurityConfigurers = webSecurityConfigurers;
}

  • T1(注释标记处)获取配置信息
@Value("#{@autowiredWebSecurityConfigurersIgnoreParents.getWebSecurityConfigurers()}"

可以看一下autowiredWebSecurityConfigurersIgnoreParents.getWebSecurityConfigurers()的源代码

public List<SecurityConfigurer<Filter, WebSecurity>> getWebSecurityConfigurers() {
List<SecurityConfigurer<Filter, WebSecurity>> webSecurityConfigurers = new ArrayList<SecurityConfigurer<Filter, WebSecurity>>();
Map<String, WebSecurityConfigurer> beansOfType = beanFactory
.getBeansOfType(WebSecurityConfigurer.class);
for (Entry<String, WebSecurityConfigurer> entry : beansOfType.entrySet()) {
webSecurityConfigurers.add(entry.getValue());
}
return webSecurityConfigurers;
}

其实我们根据debug获取到的来看,这个beansOfType 就是我们定义的继承自WebSecurityConfigurerAdapter的类,通过查看父类的定义,我们知道调用build()方法最后返回的必须是一个Filter对象,可以自行参考顶级父类(或接口)WebSecurityConfigurerSecurityBuilder

  • T2这里直接用new 来创建一个WebSecurity的对象
  • T3当有多个配置项时进行排序
  • T4进行order重复验证
  • T5将配置信息配置到webSecurity中,变量configurers中会存储这个信息

WebSecurityConfiguration中的 springSecurityFilterChain()方法

  • 为我们创建了一个名字叫做springSecurityFilterChain的Filter

    源代码:
@Bean(name = AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME)
public Filter springSecurityFilterChain() throws Exception {
boolean hasConfigurers = webSecurityConfigurers != null
&& !webSecurityConfigurers.isEmpty();
//这里的意思是我们是否有自定义配置其实就是是否有注入WebSecurityConfigurer的子类,没有的话,我默认的创建一个默认的,但是默认的我们自己不可修改
if (!hasConfigurers) {
WebSecurityConfigurerAdapter adapter = objectObjectPostProcessor
.postProcess(new WebSecurityConfigurerAdapter() {
});
//请参考上面的代码
webSecurity.apply(adapter);
}
//现在为止webSecurity对象的信息已经填充完毕,我们可以构建一个Filter
return webSecurity.build();
}
  • 请查看代码的注释,我们可以知道,到此为止,已经建立了一个Filter对象,而这个Filter将会拦截掉我们的请求,对请求进行过滤拦截,从而起到对资源进行认证保护的作用。然后这个Filter并非我们自己平时定义的Filter这么简单,这个过滤器也只是一个代理的过滤器而已,里面还会有过滤器链,下一篇文章会针对过滤器链进行编写。

2.2.3 WebSecurityConfigurerAdapter为我们做了什么

  • 还是从最重要的开始
  • 1.HttpSecurity 通过getHttp()获取,后面会详细说到这个类
    1. UserDetailsService 用户信息获取
    1. AuthenticationManager 认证管理类

      后面会详细讲解到这些信息,包括这些信息在过滤其中起到什么作用,然后最重要的是,我们要先理清楚过滤器的机制,下一篇会详细讲过滤器链

原文地址:https://www.jianshu.com/p/0c54788c94f3

Spring Security原理篇(一) 启动原理的更多相关文章

  1. Spring Security OAuth2 完全解析 (流程/原理/实战定制) —— Client / ResourceServer 篇

    一.前言 本文假设读者对 Spring Security 本身原理有一定程度的了解,假设对 OAuth2 规范流程.Jwt 有基础了解,以此来对 SpringSecurity 整合 OAuth2 有个 ...

  2. spring boot跨域请求访问配置以及spring security中配置失效的原理解析

    一.同源策略 同源策略[same origin policy]是浏览器的一个安全功能,不同源的客户端脚本在没有明确授权的情况下,不能读写对方资源. 同源策略是浏览器安全的基石. 什么是源 源[orig ...

  3. springboot(八) 嵌入式Servlet容器自动配置原理和容器启动原理

    1.嵌入式Servlet容器自动配置原理 1.1 在spring-boot-autoconfigure-1.5.9.RELEASE.jar => springboot自动配置依赖 jar包下,E ...

  4. 01 spring security入门篇

    1. 环境搭建 使用SpringBoot搭建开发环境,只需在pom.xml添加如下依赖即可. <?xml version="1.0" encoding="UTF-8 ...

  5. Spring Security 入门篇

    本文是一个笔记系列,目标是完成一个基于角色的权限访问控制系统(RBAC),有基本的用户.角色.权限管理,重点在Spring Security的各种配置.万丈高楼平地起,接下来,一步一步,由浅入深,希望 ...

  6. 【串线篇】spring boot嵌入式Servlet容器启动原理;

    什么时候创建嵌入式的Servlet容器工厂?什么时候获取嵌入式的Servlet容器并启动Tomcat: 获取嵌入式的Servlet容器工厂: 1).SpringBoot应用启动运行run方法 2).r ...

  7. 🔥🔥🔥Spring Cloud进阶篇之Eureka原理分析

    前言 之前写了几篇Spring Cloud的小白教程,相信看过的朋友对Spring Cloud中的一些应用有了简单的了解,写小白篇的目的就是为初学者建立一个基本概念,让初学者在学习的道路上建立一定的基 ...

  8. Spring Security入门篇——标签sec:authorize的使用

    Security框架可以精确控制页面的一个按钮.链接,它在页面上权限的控制实际上是通过它提供的标签来做到的 Security共有三类标签authorize authentication accessc ...

  9. Linux系统的启动原理

    Linux系统的启动原理 RHEL的启动原理BIOS自检-MBR-启动GRUB-加载内核-systemd的init进程 systemd的初始化进程加载需要的服务,挂载文件系统/etc/fstabsys ...

随机推荐

  1. Python数据分析与展示[第三周](pandas简介与数据创建)

    第三周的课程pandas 分析数据 http://pandas.pydata.org import pandas as pd 常与numpy matplotlib 一块定义 d=pd.Series(r ...

  2. 重磅!阿里云Promtheus 正式免费公测

    每日头条 重磅!容器集群监控利器 阿里云Promtheus 正式免费公测 Prometheus 作为容器生态下集群监控的首选方案,是一套开源的系统监控报警框架.2019 年7月3日,阿里云Promth ...

  3. hackerrank--- challenges/fp-update-list

    纯属为了练习haskell, 竟然贴代码都没办法高亮. challenges/fp-update-list Update the values of a list with their absolut ...

  4. python中的open函数

    open函数用于文件处理 操作文件时,一般需要经历如下步骤: 打开文件 操作文件 一.打开文件 1 文件句柄 = open('文件路径', '模式') 打开文件时,需要指定文件路径和以何等方式打开文件 ...

  5. 【JZOJ4964】【GDKOI2017模拟1.21】Rhyme

    hafy 由于多次交换邮票没有满足所有人的需求,小Z被赶出了集邮部.无处可去的小Z决定加入音乐部,为了让音乐部的人注意到自己的才华,小Z想写一首曲子.为了让自己的曲子更好听,小Z找到了一些好听曲子作为 ...

  6. Directx11教程(21) 修正程序最小化异常bug

    原文:Directx11教程(21) 修正程序最小化异常bug       很长时间竟然没有注意到,窗口最小化时候,程序会异常,今天调试水面程序时,随意间最小化了窗口,发现程序异常了.经过调试,原来程 ...

  7. JavaScript--查看代码运行效率console.time()与console.timeEnd()用法

    程序运行时间计算: <!DOCTYPE html> <html lang="en"> <head> <meta charset=" ...

  8. KiCad 5.1.0 镜像圆弧后错位问题

    KiCad 5.1.0 镜像圆弧后错位问题 看官方回复这个问题将在 5.1.3 进行修复,因为这段时间在举行 KiCon 活动. 看到这个问题并不是非常严重,不是致命的,所以已经从 5.1.0 跳到 ...

  9. maven 标签: 项目管理软件 2016-09-11 22:29 323人阅读 评论(24) 收藏

    开始接触itoo的java项目之后,也就开始接触maven,搭建环境中有一个步骤是配置maven和jboss,当时知道jboss是用来部署我们的项目的,但是maven就只知道一个更新maven,那么, ...

  10. WebGL three.js学习笔记 加载外部模型以及Tween.js动画

    WebGL three.js学习笔记 加载外部模型以及Tween.js动画 本文的程序实现了加载外部stl格式的模型,以及学习了如何把加载的模型变为一个粒子系统,并使用Tween.js对该粒子系统进行 ...