<div id="cnblogs_post_body" class="blogpost-body cnblogs-markdown"><div class="show-content-free"> <h1>1.概述</h1> <ul> <li> <code>spring security</code>有参考的中文翻译文档<a href="https://springcloud.cc/spring-security-zhcn.html" target="_blank" rel="nofollow">https://springcloud.cc/spring-security-zhcn.html</a> </li> <li>在学习<code>spring security</code>的时候,参考的书籍并非不少,线上的技术博文也是没有系统的全面的介绍,不得不去参考源代码,发费了大量时间和精力,而我试图也经过一系列的文章,能结合本身的学习经历,按部就班的表达清楚本身所理解到的点。</li> <li>全部的文章都是对源代码的解读,最后会给出一个小小的demo。</li> <li>选用的 <code>spring boot</code>版本<code>1.4.3.RELEASE</code>,<code>spring cloud</code>版本<code>Camden.SR4</code>(后面有结合网关zuul作oauth2 认证受权介绍)。版本非spring 最新版本,选用的是平时使用最多版本。</li> <li>文章是做为学习笔记性质为目的.固然若是文章能帮到有须要的朋友天然是特别开心和幸福的事情。有理解错误和不到位的点也但愿各位指出,一块儿学习一块儿成长,一直没有都没敢写公开技术文章,第一本人水平有限,第二是不但愿由于本身的错误给别人形成误导。</li> </ul> <h1>2.启动</h1> <h2>2.1 简单的开始</h2> <p>从文档中可知,spring引入咱们的项目只须要分为两步</p> <ul> <li>maven引入须要的包,spring boot中引入的spring security版本为4.1.4</li> </ul> <pre class="hljs xml"><code class="xml hljs"> <span class="hljs-tag"><span class="hljs-tag"><</span><span class="hljs-name"><span class="hljs-tag"><span class="hljs-name">dependency</span></span></span><span class="hljs-tag">></span></span> <span class="hljs-tag"><span class="hljs-tag"><</span><span class="hljs-name"><span class="hljs-tag"><span class="hljs-name">groupId</span></span></span><span class="hljs-tag">></span></span>org.springframework.boot<span class="hljs-tag"><span class="hljs-tag"></</span><span class="hljs-name"><span class="hljs-tag"><span class="hljs-name">groupId</span></span></span><span class="hljs-tag">></span></span> <span class="hljs-tag"><span class="hljs-tag"><</span><span class="hljs-name"><span class="hljs-tag"><span class="hljs-name">artifactId</span></span></span><span class="hljs-tag">></span></span>spring-boot-starter-security<span class="hljs-tag"><span class="hljs-tag"></</span><span class="hljs-name"><span class="hljs-tag"><span class="hljs-name">artifactId</span></span></span><span class="hljs-tag">></span></span> <span class="hljs-tag"><span class="hljs-tag"></</span><span class="hljs-name"><span class="hljs-tag"><span class="hljs-name">dependency</span></span></span><span class="hljs-tag">></span></span> </code></pre> <ul> <li>配置spring security(spring security官方文档给出的例子,后面简称例子1)</li> </ul> <pre class="hljs java"><code class="java hljs"><span class="hljs-meta"><span class="hljs-meta">@EnableWebSecurity</span></span> <span class="hljs-keyword"><span class="hljs-keyword">public</span></span> <span class="hljs-class"><span class="hljs-keyword"><span class="hljs-class"><span class="hljs-keyword">class</span></span></span><span class="hljs-class"> </span><span class="hljs-title"><span class="hljs-class"><span class="hljs-title">WebSecurityConfig</span></span></span><span class="hljs-class"> </span><span class="hljs-keyword"><span class="hljs-class"><span class="hljs-keyword">extends</span></span></span><span class="hljs-class"> </span><span class="hljs-title"><span class="hljs-class"><span class="hljs-title">WebSecurityConfigurerAdapter</span></span></span><span class="hljs-class"> </span></span>{javascript
<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>); }
} </code></pre>css
<h2>2.2 简单后面的繁琐</h2> <p>咱们洁简的应用spring security到咱们的项目,而后却开启了很是强大的功能,上面的例子,在内存中配置了一个用户名为user,密码为password,而且拥有USER角色的用户。咱们仍是要探究一下,spring security到底为咱们作了一些什么样的工做。<br> 咱们的入手点只有两个,<code>@EnableWebSecurity</code>注解和<code>WebSecurityConfigurerAdapter</code>这个适配器类。</p> <h3>2.2.1 @EnableWebSecurity 注解</h3> <p>注解源代码</p> <pre class="hljs css"><code class="css hljs">@<span class="hljs-keyword"><span class="hljs-keyword">Retention</span></span>(<span class="hljs-keyword"><span class="hljs-keyword">value</span></span> = java.lang.annotation.RetentionPolicy.RUNTIME) @Target(value = { <span class="hljs-selector-tag"><span class="hljs-selector-tag">java</span></span><span class="hljs-selector-class"><span class="hljs-selector-class">.lang</span></span><span class="hljs-selector-class"><span class="hljs-selector-class">.annotation</span></span><span class="hljs-selector-class"><span class="hljs-selector-class">.ElementType</span></span><span class="hljs-selector-class"><span class="hljs-selector-class">.TYPE</span></span> }) @<span class="hljs-keyword"><span class="hljs-keyword">Documented</span></span> @Import({ <span class="hljs-selector-tag"><span class="hljs-selector-tag">WebSecurityConfiguration</span></span><span class="hljs-selector-class"><span class="hljs-selector-class">.class</span></span>, <span class="hljs-selector-tag"><span class="hljs-selector-tag">SpringWebMvcImportSelector</span></span><span class="hljs-selector-class"><span class="hljs-selector-class">.class</span></span>, <span class="hljs-selector-tag"><span class="hljs-selector-tag">OAuth2ImportSelector</span></span><span class="hljs-selector-class"><span class="hljs-selector-class">.class</span></span> }) @<span class="hljs-keyword"><span class="hljs-keyword">EnableGlobalAuthentication</span></span> @Configuration public @interface EnableWebSecurity { <span class="hljs-selector-tag"><span class="hljs-selector-tag">boolean</span></span> <span class="hljs-selector-tag"><span class="hljs-selector-tag">debug</span></span>() <span class="hljs-selector-tag"><span class="hljs-selector-tag">default</span></span> <span class="hljs-selector-tag"><span class="hljs-selector-tag">false</span></span>; </code></pre> <p>此处仍是有必要简单翻译一下官方对于类的注释,以便于更加清楚的理解注解的做用<br> 注释中提到两个很重要的点,以及一个配置示例,</p> <ul> <li>第一个点:<code>@EnableWebSecurity</code>配置到拥有注解 <code>@Configuration</code>的类上,就能够获取到spring security的支持.</li> <li>第二个点: <code>WebSecurityConfigurer</code>的子类能够扩展spring security的应用</li> </ul> <p>由此可知<code>@EnableWebSecurity</code>使咱们拥有spring security的能力。<code>WebSecurityConfigurer</code> 使咱们能根据业务扩展咱们的应用,而<code>WebSecurityConfigurerAdapter</code>是<code>WebSecurityConfigurer</code> 的一个适配器,必然也是作了不少默认的工做。后面咱们会一一说到。</p> <p>从以上能够稍微总结一下咱们下一步须要探究的问题,</p> <ul> <li> <code>WebSecurityConfigurerAdapter</code>到底为咱们作了什么工做.</li> <li>上面注解的源代码中Import了一个很重要的配置类<code>WebSecurityConfiguration</code>怎样组件咱们的过滤器(或者说过滤器链)</li> </ul> <h2>2.2.2 spring security建立流程</h2> <div class="image-package"> <div class="image-container" style="max-width: 507px; max-height: 545px; background-color: transparent;">html
<div class="image-view" data-width="507" data-height="545"><img data-original-src="//upload-images.jianshu.io/upload_images/3677408-5f5de55846dbc9dd.png" data-original-width="507" data-original-height="545" data-original-format="image/png" data-original-filesize="35764" class="" style="cursor: zoom-in;" src="https://img2018.cnblogs.com/blog/1112483/201906/1112483-20190614104107048-1838982520.png"></div> </div> <div class="image-caption">spring security加载流程</div> </div> <ul> <li>若是咱们忽略掉细节,只看最重要的步骤,大概如此.下面咱们对每个步骤来作相应的源代码解释</li> </ul> <h3> <code>WebSecurityConfiguration</code>中的 <code>setFilterChainProxySecurityConfigurer()</code>方法</h3> <pre class="hljs java"><code class="java hljs"><span class="hljs-meta"><span class="hljs-meta">@Autowired</span></span>(required = <span class="hljs-keyword"><span class="hljs-keyword">false</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">setFilterChainProxySecurityConfigurer</span></span></span><span class="hljs-params"><span class="hljs-function"><span class="hljs-params">( ObjectPostProcessor<Object> objectPostProcessor, //T1 使用@Value获取到配置信息 @Value(</span></span><span class="hljs-string"><span class="hljs-function"><span class="hljs-params"><span class="hljs-string">"#{@autowiredWebSecurityConfigurersIgnoreParents.getWebSecurityConfigurers()}"</span></span></span></span><span class="hljs-function"><span class="hljs-params">)</span></span></span><span class="hljs-function"> List<SecurityConfigurer<Filter, WebSecurity>> webSecurityConfigurers) </span><span class="hljs-keyword"><span class="hljs-function"><span class="hljs-keyword">throws</span></span></span><span class="hljs-function"> Exception </span></span>{java
<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<Filter, WebSecurity> 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> && 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<Filter, WebSecurity> 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; }
</code></pre>web
<ul> <li> <code>T1</code>(注释标记处)获取配置信息</li> </ul> <pre class="hljs ruby"><code class="ruby hljs">@Value(<span class="hljs-string"><span class="hljs-string">"</span><span class="hljs-subst"><span class="hljs-string"><span class="hljs-subst">#{@autowiredWebSecurityConfigurersIgnoreParents.getWebSecurityConfigurers()}</span></span></span><span class="hljs-string">"</span></span> </code></pre> <p>能够看一下autowiredWebSecurityConfigurersIgnoreParents.getWebSecurityConfigurers()的源代码</p> <pre class="hljs javascript"><code class="javascript hljs">public List<SecurityConfigurer<Filter, WebSecurity>> getWebSecurityConfigurers() { List<SecurityConfigurer<Filter, WebSecurity>> webSecurityConfigurers = <span class="hljs-keyword"><span class="hljs-keyword">new</span></span> ArrayList<SecurityConfigurer<Filter, WebSecurity>>(); <span class="hljs-built_in"><span class="hljs-built_in">Map</span></span><<span class="hljs-built_in"><span class="hljs-built_in">String</span></span>, WebSecurityConfigurer> beansOfType = beanFactory .getBeansOfType(WebSecurityConfigurer.class); <span class="hljs-keyword"><span class="hljs-keyword">for</span></span> (Entry<<span class="hljs-built_in"><span class="hljs-built_in">String</span></span>, WebSecurityConfigurer> entry : beansOfType.entrySet()) { webSecurityConfigurers.add(entry.getValue()); } <span class="hljs-keyword"><span class="hljs-keyword">return</span></span> webSecurityConfigurers; } </code></pre> <p>其实咱们根据debug获取到的来看,这个beansOfType 就是咱们定义的继承自WebSecurityConfigurerAdapter的类,经过查看父类的定义,咱们知道调用build()方法最后返回的必须是一个Filter对象,能够自行参考顶级父类(或接口)<code>WebSecurityConfigurer</code>和<code>SecurityBuilder</code></p> <ul> <li> <code>T2</code>这里直接用new 来建立一个WebSecurity的对象</li> <li> <code>T3</code>当有多个配置项时进行排序</li> <li> <code>T4</code>进行order重复验证</li> <li> <code>T5</code>将配置信息配置到webSecurity中,变量configurers中会存储这个信息</li> </ul> <h3> <code>WebSecurityConfiguration</code>中的 <code>springSecurityFilterChain()</code>方法</h3> <ul> <li>为咱们建立了一个名字叫作<code>springSecurityFilterChain</code>的Filter<br> 源代码:</li> </ul> <pre class="hljs java"><code class="java hljs"><span class="hljs-meta"><span class="hljs-meta">@Bean</span></span>(name = AbstractSecurityWebApplicationInitializer.DEFAULT_FILTER_NAME) <span class="hljs-function"><span class="hljs-keyword"><span class="hljs-function"><span class="hljs-keyword">public</span></span></span><span class="hljs-function"> Filter </span><span class="hljs-title"><span class="hljs-function"><span class="hljs-title">springSecurityFilterChain</span></span></span><span class="hljs-params"><span class="hljs-function"><span class="hljs-params">()</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>{ <span class="hljs-keyword"><span class="hljs-keyword">boolean</span></span> hasConfigurers = webSecurityConfigurers != <span class="hljs-keyword"><span class="hljs-keyword">null</span></span> && !webSecurityConfigurers.isEmpty(); <span class="hljs-comment"><span class="hljs-comment">//这里的意思是咱们是否有自定义配置其实就是是否有注入WebSecurityConfigurer的子类,没有的话,我默认的建立一个默认的,可是默认的咱们本身不可修改</span></span> <span class="hljs-keyword"><span class="hljs-keyword">if</span></span> (!hasConfigurers) { WebSecurityConfigurerAdapter adapter = objectObjectPostProcessor .postProcess(<span class="hljs-keyword"><span class="hljs-keyword">new</span></span> WebSecurityConfigurerAdapter() { }); <span class="hljs-comment"><span class="hljs-comment">//请参考上面的代码</span></span> webSecurity.apply(adapter); } <span class="hljs-comment"><span class="hljs-comment">//如今为止webSecurity对象的信息已经填充完毕,咱们能够构建一个Filter</span></span> <span class="hljs-keyword"><span class="hljs-keyword">return</span></span> webSecurity.build(); } </code></pre> <ul> <li>请查看代码的注释,咱们能够知道,到此为止,已经创建了一个<code>Filter</code>对象,而这个<code>Filter</code>将会拦截掉咱们的请求,对请求进行过滤拦截,从而起到对资源进行认证保护的做用。而后这个<code>Filter</code>并不是咱们本身平时定义的<code>Filter</code>这么简单,这个过滤器也只是一个代理的过滤器而已,里面还会有过滤器链,下一篇文章会针对过滤器链进行编写。</li> </ul> <h2>2.2.3 <code>WebSecurityConfigurerAdapter</code>为咱们作了什么</h2> <ul> <li>仍是从最重要的开始</li> <li>1.<code>HttpSecurity</code> 经过getHttp()获取,后面会详细说到这个类</li> <li><ol start="2"> <li> <code>UserDetailsService</code> 用户信息获取</li> </ol></li> <li><ol start="3"> <li> <code>AuthenticationManager</code> 认证管理类<br> 后面会详细讲解到这些信息,包括这些信息在过滤其中起到什么做用,而后最重要的是,咱们要先理清楚过滤器的机制,下一篇会详细讲过滤器链</li> </ol></li> </ul> 原文地址:https://www.jianshu.com/p/0c54788c94f3 </div> </div>spring