Spring Security 4.2.3 Filters 解析
一、 熟悉一个模块的最快方法
1. 配置logback文件,打印相应的debug信息
2. 根据相应的信息,打断点查看执行结果
二、spring 使用 DelegatingFilterProxy 管理 filter chain
allow the IoC container to manage the lifecycle instead of the servlet container
org.springframework.web.filter.DelegatingFilterProxy 是 Spring 中定义的一个 Filter 实现类,其作用是代理真正的 Filter 实现类,
也就是说在调用 DelegatingFilterProxy 的 doFilter() 方法时实际上调用的是其代理 Filter 的 doFilter() 方法。使用 DelegatingFilterProxy
的好处就是Filter 类可以使用 Spring 的依赖注入机制方便自由的使用 ApplicationContext 中的 bean。
需要注意的是被代理的 Filter 的初始化方法 init() 和销毁方法 destroy() 默认是不会被执行的。通过设置 DelegatingFilterProxy 的
targetFilterLifecycle 属性为 true,可以使被代理 Filter 与 DelegatingFilterProxy 具有同样的生命周期。
三、 FilterChainProxy
DelegatingFilterProxy 代理的就是一个 FilterChainProxy。一个 FilterChainProxy 中可以包含有多个 FilterChain,但是某个请求
只会对应一个 FilterChain,而一个 FilterChain 中又可以包含有多个 Filter。当我们使用 Spring Security 时,系统会自动为我们
注册一个名为 springSecurityFilterChain, 类型为 FilterChainProxy 的 bean(可查看HttpSecurityBeanDefinitionParser)。
Request Firewalling
An HttpFirewall
instance is used to validate incoming requests and create a wrapped request which provides consistent path
values for matching against. See DefaultHttpFirewall
, for more information on the type of attacks which the default i
mplementation protects against. A custom implementation can be injected to provide stricter control over the request contents
or if an application needs to support certain types of request which are rejected by default.
Note that this means that you must use the Spring Security filters in combination with a FilterChainProxy
if you want this
protection. Don't define them explicitly in your web.xml
file.
FilterChainProxy
will use the firewall instance to obtain both request and response objects which will be fed down the filter chain,
so it is also possible to use this functionality to control the functionality of the response. When the request has passed through the
security filter chain, the reset
method will be called. With the default implementation this means that the original values of
servletPath
and pathInfo
will be returned thereafter, instead of the modified ones used for security pattern matching.
四、 AuthenticationManager 和 AuthenticationProvider
AuthenticationManager 是一个用来处理认证请求的接口。在其中只定义了一个方法 authenticate(),该方法只接收一个代表认证请求的
Authentication对象作为参数,如果认证成功,则会返回一个封装了当前用户权限等信息的 Authentication 对象进行返回。
public Authentication authenticate(Authentication authentication) throws AuthenticationException {
Class<? extends Authentication> toTest = authentication.getClass();
AuthenticationException lastException = null;
Authentication result = null;
boolean debug = logger.isDebugEnabled();
//使用authenticationProvider列表处理认证请求
for (AuthenticationProvider provider : getProviders()) {
if (!provider.supports(toTest)) {
continue;
} if (debug) {
logger.debug("Authentication attempt using " + provider.getClass().getName());
} try {
result = provider.authenticate(authentication);
//认证成功,跳出循环
if (result != null) {
copyDetails(authentication, result);
break;
}
}
catch (AccountStatusException e) {
prepareException(e, authentication);
// SEC-546: Avoid polling additional providers if auth failure is due to
// invalid account status
throw e;
}
catch (InternalAuthenticationServiceException e) {
prepareException(e, authentication);
throw e;
}
catch (AuthenticationException e) {
lastException = e;
}
}
//没有结果,重试认证
if (result == null && parent != null) {
// Allow the parent to try.
try {
result = parent.authenticate(authentication);
}
catch (ProviderNotFoundException e) {
// ignore as we will throw below if no other exception occurred prior to
// calling parent and the parent
// may throw ProviderNotFound even though a provider in the child already
// handled the request
}
catch (AuthenticationException e) {
lastException = e;
}
}
//认证成功,发布认证结果
if (result != null) {
if (eraseCredentialsAfterAuthentication
&& (result instanceof CredentialsContainer)) {
// Authentication is complete. Remove credentials and other secret data
// from authentication
((CredentialsContainer) result).eraseCredentials();
} eventPublisher.publishAuthenticationSuccess(result);
return result;
} // Parent was null, or didn't authenticate (or throw an exception). if (lastException == null) {
lastException = new ProviderNotFoundException(messages.getMessage(
"ProviderManager.providerNotFound",
new Object[] { toTest.getName() },
"No AuthenticationProvider found for {0}"));
} prepareException(lastException, authentication); throw lastException;
}
1.认证过程
在 Spring Security 中,AuthenticationManager 的默认实现是 ProviderManager,而且它不直接自己处理认证请求,而是委托给其所配
置的 AuthenticationProvider 列表,然后会依次使用每一个 AuthenticationProvider 进行认证,如果有一个 AuthenticationProvider 认
证后的结果不为 null,则表示该 AuthenticationProvider 已经认证成功,之后的 AuthenticationProvider 将不再继续认证。然后直接以该
AuthenticationProvider 的认证结果作为 ProviderManager 的认证结果。如果所有的 AuthenticationProvider 的认证结果都为 null,则表
示认证失败,将抛出一个 ProviderNotFoundException。
2. 校验认证
校验认证请求最常用的方法是根据请求的用户名加载对应的 UserDetails,然后比对 UserDetails 的密码与认证请求的密码是否一致。
如DaoAuthenticationProvider其内部使用 UserDetailsService 来负责加载 UserDetails。在认证成功以后会使用加载的
UserDetails 来封装要返回的 Authentication 对象,加载的 UserDetails 对象是包含用户权限等信息的。认证成功返回的 Authentication
对象将会保存在当前的 SecurityContext 中。
4. 在 request 之间共享 SecurityContext
既然 SecurityContext 是存放在 ThreadLocal 中的,而且在每次权限鉴定的时候都是从 ThreadLocal 中获取 SecurityContext 中对应的
Authentication 所拥有的权限,但不同的 request 是不同的线程,为什么每次都可以从 ThreadLocal 中获取到当前用户对应的 SecurityContext 呢?
每次请求开始的时候从 session 中获取 SecurityContext,然后把它设置给 SecurityContextHolder
参考:
极客学院:初识Spring Security
Spring Security 4.2.3 Filters 解析的更多相关文章
- 认证与授权】Spring Security系列之认证流程解析
上面我们一起开始了Spring Security的初体验,并通过简单的配置甚至零配置就可以完成一个简单的认证流程.可能我们都有很大的疑惑,这中间到底发生了什么,为什么简单的配置就可以完成一个认证流程啊 ...
- Spring Security 登录校验 源码解析
传统情况下,在过滤器中做权限验证,Spring Secuirty也是在Filter中进行权限验证. 创建并注册过滤器 package com.awizdata.edubank.config; impo ...
- Spring Security 访问控制 源码解析
上篇 Spring Security 登录校验 源码解析 分析了使用Spring Security时用户登录时验证并返回token过程,本篇分析下用户带token访问时,如何验证用户登录状态及权限问 ...
- Spring Security OAuth2 开发指南
官方原文:http://projects.spring.io/spring-security-oauth/docs/oauth2.html 翻译及修改补充:Alex Liao. 转载请注明来源:htt ...
- OAuth2.0学习(2-1)Spring Security OAuth2.0 开发指南
开发指南:http://www.cnblogs.com/xingxueliao/p/5911292.html Spring OAuth2.0 提供者实现原理: Spring OAuth2.0提供者实际 ...
- Spring Security OAuth2 开发指南(非最新版本)
请注意哈,本文翻译的时候,官网的的版本和本文翻译的时候是一一对应的. 但是官网已经更新文档和概念了,因此和本文翻译的就不在是同一个范围了. 因此我已经将标题修改为(非最新版本),各位老铁直接看官网就可 ...
- Spring Security 上
Spring Security 上 Security-dome 1.创建项目 创建一个Spring Boot项目,不用加入什么依赖 2.导入依赖 <dependencies> <!- ...
- 【Spring】关于Boot应用中集成Spring Security你必须了解的那些事
Spring Security Spring Security是Spring社区的一个顶级项目,也是Spring Boot官方推荐使用的Security框架.除了常规的Authentication和A ...
- Spring Boot中集成Spring Security 专题
check to see if spring security is applied that the appropriate resources are permitted: @Configurat ...
随机推荐
- DWZ使用中遇到的坑
DWZ官方文档中关于文件上传表单的提交: 因为Ajax不支持enctype="multipart/form-data" 所以用隐藏iframe来处理无刷新表单提交. <for ...
- [OpenCV] Samples 16: Decompose and Analyse RGB channels
物体的颜色特征决定了灰度处理不是万能,对RGB分别处理具有相当的意义. #include <iostream> #include <stdio.h> #include &quo ...
- Linux设备驱动剖析之Input(一)
前言 以前在移植Qt到开发板上时只知道在配置文件中需要指定触摸屏的设备文件/dev/input/event0,仅此而已.直到一年半前突然想到用红外遥控器控制Tiny6410开发板上的Android系统 ...
- 搞懂MapReduce
MapReduce的主要思想就是将计算任务分发至多台计算机(slave),然后master综合计算机结果.所以就涉及到多台计算机通信和同步的问题,这个应该由hadoop完成,把环境配置好后就像单机操作 ...
- 免费的SSL证书(LINUX)
贫穷限制了我的SSL. 说起来也简单,免费的SSL证书授权机构,我使用的是Certbot 选择服务器开启的服务,像我php之流,无非apache和nginx,然后选择使用的服务器类型.嗯,补充一句,这 ...
- 洛谷1443 马的遍历【bfs】
题目链接:https://www.luogu.org/problemnew/show/P1443 题意: 给一个n*m的棋盘,马在上面走(规则就是象棋中的规则,详细见代码dx,dy数组定义) 问棋盘上 ...
- pycharm 下的djiango使用
创建工程可以在虚拟环境下运行,创建工程后使用命令 在python 下的命令窗口(Terminal) python3 manage.py startapp django_web (或者 python3替 ...
- Codeforces 670F - Restore a Number - [字符串]
题目链接:https://codeforces.com/contest/670/problem/F 题意: 有一个非负整数 $n$,在它的右侧添上它的位数后,被发送出去:例如 $6510$,加上位数 ...
- [No000012B]WPF(3/7)有趣的边框和画刷[译]
介绍 边框是每个WPF程序的主要构成块.在我现在的程序中,我使用了很多的边框来装饰界面.从把边框直接放到窗口中到把边框放到控件模板和列表项中,边框在创建一个好的应用界面上扮演了一个非常重要的角色.在这 ...
- tensorflow的assgin方法
官网API是这么说的 This operation outputs a Tensor that holds the new value of 'ref' after the value has bee ...