聊聊FilterSecurityInterceptor
为什么80%的码农都做不了架构师?>>>
序
本文就来研究一下spring security的FilterSecurityInterceptor
问题
前面的文章讲了SecurityContextPersistenceFilter是如何将context从session读取并写入的。其中还讲到了AbstractAuthenticationProcessingFilter是如何将鉴权成功的authentication写入context的。那么spring security是如何处理没有authentication的请求呢。答案就在FilterSecurityInterceptor。
filter顺序
spring security内置的各种filter:
Alias | Filter Class | Namespace Element or Attribute |
---|---|---|
CHANNEL_FILTER | ChannelProcessingFilter | http/intercept-url@requires-channel |
SECURITY_CONTEXT_FILTER | SecurityContextPersistenceFilter | http |
CONCURRENT_SESSION_FILTER | ConcurrentSessionFilter | session-management/concurrency-control |
HEADERS_FILTER | HeaderWriterFilter | http/headers |
CSRF_FILTER | CsrfFilter | http/csrf |
LOGOUT_FILTER | LogoutFilter | http/logout |
X509_FILTER | X509AuthenticationFilter | http/x509 |
PRE_AUTH_FILTER | AbstractPreAuthenticatedProcessingFilter Subclasses | N/A |
CAS_FILTER | CasAuthenticationFilter | N/A |
FORM_LOGIN_FILTER | UsernamePasswordAuthenticationFilter | http/form-login |
BASIC_AUTH_FILTER | BasicAuthenticationFilter | http/http-basic |
SERVLET_API_SUPPORT_FILTER | SecurityContextHolderAwareRequestFilter | http/@servlet-api-provision |
JAAS_API_SUPPORT_FILTER | JaasApiIntegrationFilter | http/@jaas-api-provision |
REMEMBER_ME_FILTER | RememberMeAuthenticationFilter | http/remember-me |
ANONYMOUS_FILTER | AnonymousAuthenticationFilter | http/anonymous |
SESSION_MANAGEMENT_FILTER | SessionManagementFilter | session-management |
EXCEPTION_TRANSLATION_FILTER | ExceptionTranslationFilter | http |
FILTER_SECURITY_INTERCEPTOR | FilterSecurityInterceptor | http |
SWITCH_USER_FILTER | SwitchUserFilter | N/A |
FilterSecurityInterceptor
spring-security-web-4.2.3.RELEASE-sources.jar!/org/springframework/security/web/access/intercept/FilterSecurityInterceptor.java
/*** Performs security handling of HTTP resources via a filter implementation.* <p>* The <code>SecurityMetadataSource</code> required by this security interceptor is of* type {@link FilterInvocationSecurityMetadataSource}.* <p>* Refer to {@link AbstractSecurityInterceptor} for details on the workflow.* </p>** @author Ben Alex* @author Rob Winch*/
public class FilterSecurityInterceptor extends AbstractSecurityInterceptor implementsFilter {
/*** Method that is actually called by the filter chain. Simply delegates to the* {@link #invoke(FilterInvocation)} method.** @param request the servlet request* @param response the servlet response* @param chain the filter chain** @throws IOException if the filter chain fails* @throws ServletException if the filter chain fails*/public void doFilter(ServletRequest request, ServletResponse response,FilterChain chain) throws IOException, ServletException {FilterInvocation fi = new FilterInvocation(request, response, chain);invoke(fi);}
public void invoke(FilterInvocation fi) throws IOException, ServletException {if ((fi.getRequest() != null)&& (fi.getRequest().getAttribute(FILTER_APPLIED) != null)&& observeOncePerRequest) {// filter already applied to this request and user wants us to observe// once-per-request handling, so don't re-do security checkingfi.getChain().doFilter(fi.getRequest(), fi.getResponse());}else {// first time this request being called, so perform security checkingif (fi.getRequest() != null) {fi.getRequest().setAttribute(FILTER_APPLIED, Boolean.TRUE);}InterceptorStatusToken token = super.beforeInvocation(fi);try {fi.getChain().doFilter(fi.getRequest(), fi.getResponse());}finally {super.finallyInvocation(token);}super.afterInvocation(token, null);}}//......
}
所有的请求到了这一个filter,如果这个filter之前没有执行过的话,那么首先执行的InterceptorStatusToken token = super.beforeInvocation(fi);这个是由AbstractSecurityInterceptor提供。它就是spring security处理鉴权的入口。
AbstractSecurityInterceptor
spring-security-core-4.2.3.RELEASE-sources.jar!/org/springframework/security/access/intercept/AbstractSecurityInterceptor.java
protected InterceptorStatusToken beforeInvocation(Object object) {Assert.notNull(object, "Object was null");final boolean debug = logger.isDebugEnabled();if (!getSecureObjectClass().isAssignableFrom(object.getClass())) {throw new IllegalArgumentException("Security invocation attempted for object "+ object.getClass().getName()+ " but AbstractSecurityInterceptor only configured to support secure objects of type: "+ getSecureObjectClass());}Collection<ConfigAttribute> attributes = this.obtainSecurityMetadataSource().getAttributes(object);if (attributes == null || attributes.isEmpty()) {if (rejectPublicInvocations) {throw new IllegalArgumentException("Secure object invocation "+ object+ " was denied as public invocations are not allowed via this interceptor. "+ "This indicates a configuration error because the "+ "rejectPublicInvocations property is set to 'true'");}if (debug) {logger.debug("Public object - authentication not attempted");}publishEvent(new PublicInvocationEvent(object));return null; // no further work post-invocation}if (debug) {logger.debug("Secure object: " + object + "; Attributes: " + attributes);}if (SecurityContextHolder.getContext().getAuthentication() == null) {credentialsNotFound(messages.getMessage("AbstractSecurityInterceptor.authenticationNotFound","An Authentication object was not found in the SecurityContext"),object, attributes);}Authentication authenticated = authenticateIfRequired();// Attempt authorizationtry {this.accessDecisionManager.decide(authenticated, object, attributes);}catch (AccessDeniedException accessDeniedException) {publishEvent(new AuthorizationFailureEvent(object, attributes, authenticated,accessDeniedException));throw accessDeniedException;}if (debug) {logger.debug("Authorization successful");}if (publishAuthorizationSuccess) {publishEvent(new AuthorizedEvent(object, attributes, authenticated));}// Attempt to run as a different userAuthentication runAs = this.runAsManager.buildRunAs(authenticated, object,attributes);if (runAs == null) {if (debug) {logger.debug("RunAsManager did not change Authentication object");}// no further work post-invocationreturn new InterceptorStatusToken(SecurityContextHolder.getContext(), false,attributes, object);}else {if (debug) {logger.debug("Switching to RunAs Authentication: " + runAs);}SecurityContext origCtx = SecurityContextHolder.getContext();SecurityContextHolder.setContext(SecurityContextHolder.createEmptyContext());SecurityContextHolder.getContext().setAuthentication(runAs);// need to revert to token.Authenticated post-invocationreturn new InterceptorStatusToken(origCtx, true, attributes, object);}}
这里调用了accessDecisionManager来进行判断,如果没有登录态,在到达这个filter之前会先经过AnonymousAuthenticationFilter.java,其Authentication的值为AnonymousAuthenticationToken。如果匿名请求需要登录态的url,或者权限不够,则抛出AccessDeniedException。
小结
spring security两个入口filter分别如下:
- AbstractAuthenticationProcessingFilter(
主要处理登录
) - FilterSecurityInterceptor(
主要处理鉴权
)
而SecurityContextPersistenceFilter主要是为这两个filter准备context。
转载于:https://my.oschina.net/go4it/blog/1591160
聊聊FilterSecurityInterceptor相关推荐
- 面向对象设计原则_聊聊面向对象的6大设计原则
程序员都知道编程有 3 大类:面向过程.面向对象.面向函数.面向对象是被讨论的最多的,个人认为,这是因为 Java 之类的编程语言有强大的用户基础,本质还是因为比较符合人的直觉. 说到面向对象,大家可 ...
- python邮件发送哪个好_最全总结!聊聊 Python 发送邮件的几种方式
1. 前言 邮件,作为最正式规范的沟通方式,在日常办公过程中经常被用到 我们都知道 Python内置了对 SMTP 的支持,可以发送纯文本.富文本.HTML 等格式的邮件 本文将聊聊利用 Python ...
- 今天聊聊分布式锁 No.86
好了切入正题,一直在工作中会聊到很多锁的问题,今天跟大家一起闲聊一下,究竟什么是锁,为什么需要锁,以及分布式的情况下,怎么设计和实现锁. 什么是锁? 明·魏禧<大铁椎传>上是这样解释的: ...
- 聊聊找工作中的项目经验问题(推荐系统和智能问答)
在求职过程中有这么一句话叫做"金九银十",也就是说,很多时候,求职的黄金时期就是在九月份和十月份,这两个月份中企业需求是最多的,求职的成功率也是最高的.但是随着AI方面的人才越来越 ...
- 聊聊Service Mesh:linkerd
[编者的话]随着企业逐渐将传统的单体应用向微服务或云原生应用的转变,虽然微服务或者云原生应用能给企业带来更多的好处,但也会带来一些具有挑战的问题,如怎么管理从单体应用转向微服务所带来的服务间通讯的复杂 ...
- 庖丁解牛迭代器,聊聊那些藏在幕后的秘密
0x00 前言 \\ 在我之前的一篇博客<细说C#:不是"栈类型"的值类型,从生命周期聊存储位置>的最后,我以总结和后记的方式涉及到一部分迭代器的知识.但是觉得还是不够 ...
- 聊聊Unsafe的一些使用技巧
记得初学 Java 那会,刚学完语法基础,就接触到了反射这个 Java 提供的特性,尽管在现在看来,这是非常基础的知识点,但那时候无疑是兴奋的,瞬间觉得自己脱离了"Java 初学者" ...
- 聊聊 TCP 长连接和心跳那些事
1 前言 可能很多 Java 程序员对 TCP 的理解只有一个三次握手,四次挥手的认识,我觉得这样的原因主要在于 TCP 协议本身稍微有点抽象(相比较于应用层的 HTTP 协议):其次,非框架开发者不 ...
- 聊聊算法在面试中的地位
前段时间,有一位好友找到我,向我打听阿里社招笔试是否看重算法题的考察,我给予了肯定的答复.他表现的有些沮丧,表示自己工程底子很扎实,框架源码也研究地很透彻,唯独算法能力不行,leetcode 上的简单 ...
最新文章
- 2020 年度最佳的23个机器学习项目!(附源代码)
- 如何给邮件添加背景颜色
- ubuntu系统操作常见错误
- Win-MASM64汇编语言-MUL/DIV
- STC学习:导航按键与数字按键综合控制数码管
- Makefile文件生成 GNU Autotools的使用方法
- 数据治理之数据质量管理
- UGNX1957安装说明视频教程
- 数论入门符号_大o符号快速入门
- webQQ协议——模拟登录
- 接上文安装完opencv后安装viz模块
- java web报表开发_2020主流JAVA WEB报表工具对比
- galgame序列号怎么查看_国行Switch能完整体验的游戏有哪些?Switch支架掉了怎么办? | Jump指南...
- window10 1060 caffe 安装
- Go开发 之 容器(数组Array、切片slice、映射map、列表list)
- Service START_NOT_STICKY、START_STICKY
- 青春无言│用技术定格毕业季最美好的回忆
- 上海踩踏事件所想,莫把应急预案当摆设
- wampserver 2.4 配置虚拟主机
- 戴森“新我发现所”苏州线下体验展启幕 以颠覆性科技传递护发造型新理念
热门文章
- 考试君 - 基于.NET 5语言的Furion框架开发在线考试系统
- 微信小程序商城,微信小程序微店,长期维护版本
- 三、Linux 开机、重启和用户登录注销
- 云商城云小店官网源码-修复30套模板支持一键对接各大系统
- cnblog div+CSS 布局常识 8问
- 项目所需的应用程序未安装,确保已安装项目类型(.csproj)的应用程序的解决办法...
- 什么是Viewport Meta(width详解)及在手机上的应用
- Magento教程 20:仅限会员留言的产品评论设定!
- SVG 教程 (五)文本,Stroke 属性,SVG 滤镜,SVG 模糊效果
- 网站统计:第一方Cookie和第三方Cookie