- 浏览: 1193386 次
- 性别:
- 来自: 杭州
文章分类
最新评论
-
insistboy:
写的太棒了,受不了
WebLogic11g-创建域(Domain) -
goldyeah:
厉害了 困扰我大半个月的问题解决了 谢谢博主
WebLogic11g-单双向SSL配置(以Springside3为例) -
zy315351965:
404伤不起
开源流程引擎Snaker -
nannan408:
双向的时候谷歌提示“不接受您的登录证书,或者您可能没有提供登录 ...
WebLogic11g-单双向SSL配置(以Springside3为例) -
一颗赛艇:
不成功啊。启动有问题 <Security> < ...
WebLogic11g-单双向SSL配置(以Springside3为例)
FilterSecurityInterceptor过滤器对应的类路径为
org.springframework.security.web.access.intercept.FilterSecurityInterceptor
这个filter是filterchain中比较复杂,也是比较核心的过滤器,主要负责授权的工作
在看这个filter源码之前,先来看看spring是如何构造filter这个bean的
具体的构造过程的代码片段为
现在再仔细分析创建元数据资源的bean过程
通过以上的bean构造过程,FilterSecurityInterceptor所依赖的决策管理器、认证管理器、安全元数据资源都具备了,该让FilterSecurityInterceptor干活了,其源码为
继续看父类的beforeInvocation方法,其中省略了一些不重要的代码片段
增加说明
这里获取的是权限列表信息,比如说有这个配置
<security:intercept-url pattern="/index.jsp*" access="ROLE_USER,ROLE_ADMIN"/>
如果现在发起一个请求时index.jsp,那么根据这个请求返回的attributes集合就是分别包含ROLE_USER,ROLE_ADMIN属性的两个SecurityConfig对象
至于请求url如何匹配的,大家可以通过阅读DefaultFilterInvocationSecurityMetadataSource类的源码,实际上,这里用到了spring的路径匹配工具类org.springframework.util.AntPathMatcher
AntPathMatcher匹配方式的通配符有三种:
?(匹配任何单字符),*(匹配0或者任意数量的字符),**(匹配0或者更多的目录)
由于之前在bean的定义过程已经知道决策管理器是AffirmativeBased,接着看AffirmativeBased的决策过程
实际上,有三种决策管理器,分别为AffirmativeBased、ConsensusBased、UnanimousBased,各自决策的区别是:
AffirmativeBased:只要有一个voter投同意票,就授权成功
ConsensusBased:只要投同意票的大于投反对票的,就授权成功
UnanimousBased:需要一致通过才授权成功具体决策规则很简单,只是根据voter返回的结果做处理
接下来,分别看RoleVoter、AuthenticatedVoter的源码
RoleVoter:
AuthenticatedVoter:
由于RoleVoter在list列表中的位置处于AuthenticatedVoter前面,只要RoleVoter通过,就不会再执行AuthenticatedVoter了。实际上AuthenticatedVoter只会对IS_AUTHENTICATED_FULLY、IS_AUTHENTICATED_REMEMBERED、IS_AUTHENTICATED_ANONYMOUSLY三种权限做vote处理。
org.springframework.security.web.access.intercept.FilterSecurityInterceptor
这个filter是filterchain中比较复杂,也是比较核心的过滤器,主要负责授权的工作
在看这个filter源码之前,先来看看spring是如何构造filter这个bean的
具体的构造过程的代码片段为
//这个方法源自HttpConfigurationBuilder类 void createFilterSecurityInterceptor(BeanReference authManager) { //判断是否配置了use-expressions属性 boolean useExpressions = FilterInvocationSecurityMetadataSourceParser.isUseExpressions(httpElt); //根据intercept-url标签列表创建授权需要的元数据信息。后面仔细分析 BeanDefinition securityMds = FilterInvocationSecurityMetadataSourceParser.createSecurityMetadataSource(interceptUrls, httpElt, pc); RootBeanDefinition accessDecisionMgr; //创建voter列表 ManagedList<BeanDefinition> voters = new ManagedList<BeanDefinition>(2); //如果是使用了表达式,使用WebExpressionVoter //没使用表达式,就使用RoleVoter、AuthenticatedVoter if (useExpressions) { voters.add(new RootBeanDefinition(WebExpressionVoter.class)); } else { voters.add(new RootBeanDefinition(RoleVoter.class)); voters.add(new RootBeanDefinition(AuthenticatedVoter.class)); } //定义授权的决策管理类AffirmativeBased accessDecisionMgr = new RootBeanDefinition(AffirmativeBased.class); //添加依赖的voter列表 accessDecisionMgr.getPropertyValues().addPropertyValue("decisionVoters", voters); accessDecisionMgr.setSource(pc.extractSource(httpElt)); // Set up the access manager reference for http String accessManagerId = httpElt.getAttribute(ATT_ACCESS_MGR); //如果未定义access-decision-manager-ref属性,就使用默认的 //AffirmativeBased if (!StringUtils.hasText(accessManagerId)) { accessManagerId = pc.getReaderContext().generateBeanName(accessDecisionMgr); pc.registerBeanComponent(new BeanComponentDefinition(accessDecisionMgr, accessManagerId)); } //创建FilterSecurityInterceptor过滤器 BeanDefinitionBuilder builder = BeanDefinitionBuilder.rootBeanDefinition(FilterSecurityInterceptor.class); //添加决策管理器 builder.addPropertyReference("accessDecisionManager", accessManagerId); //添加认证管理类 builder.addPropertyValue("authenticationManager", authManager); if ("false".equals(httpElt.getAttribute(ATT_ONCE_PER_REQUEST))) { builder.addPropertyValue("observeOncePerRequest", Boolean.FALSE); } //添加授权需要的安全元数据资源 builder.addPropertyValue("securityMetadataSource", securityMds); BeanDefinition fsiBean = builder.getBeanDefinition(); //向ioc容器注册bean String fsiId = pc.getReaderContext().generateBeanName(fsiBean); pc.registerBeanComponent(new BeanComponentDefinition(fsiBean,fsiId)); // Create and register a DefaultWebInvocationPrivilegeEvaluator for use with taglibs etc. BeanDefinition wipe = new RootBeanDefinition(DefaultWebInvocationPrivilegeEvaluator.class); wipe.getConstructorArgumentValues().addGenericArgumentValue(new RuntimeBeanReference(fsiId)); pc.registerBeanComponent(new BeanComponentDefinition(wipe, pc.getReaderContext().generateBeanName(wipe))); this.fsi = new RuntimeBeanReference(fsiId); }
现在再仔细分析创建元数据资源的bean过程
static BeanDefinition createSecurityMetadataSource(List<Element> interceptUrls, Element elt, ParserContext pc) { //创建Url处理类,有两个实现:AntUrlPathMatcher、RegexUrlPathMatcher UrlMatcher matcher = HttpSecurityBeanDefinitionParser.createUrlMatcher(elt); boolean useExpressions = isUseExpressions(elt); //解析intercept-url标签,构造所有需要拦截url的map信息 //map中的key:RequestKey的bean定义,value:SecurityConfig的bean定义 ManagedMap<BeanDefinition, BeanDefinition> requestToAttributesMap = parseInterceptUrlsForFilterInvocationRequestMap( interceptUrls, useExpressions, pc); BeanDefinitionBuilder fidsBuilder; if (useExpressions) { //定义表达式处理类的bean Element expressionHandlerElt = DomUtils.getChildElementByTagName(elt, Elements.EXPRESSION_HANDLER); String expressionHandlerRef = expressionHandlerElt == null ? null : expressionHandlerElt.getAttribute("ref"); if (StringUtils.hasText(expressionHandlerRef)) { logger.info("Using bean '" + expressionHandlerRef + "' as web SecurityExpressionHandler implementation"); } else { BeanDefinition expressionHandler = BeanDefinitionBuilder.rootBeanDefinition(DefaultWebSecurityExpressionHandler.class).getBeanDefinition(); expressionHandlerRef = pc.getReaderContext().generateBeanName(expressionHandler); pc.registerBeanComponent(new BeanComponentDefinition(expressionHandler, expressionHandlerRef)); } //定义表达式类型的FilterInvocationSecurityMetadataSource fidsBuilder = BeanDefinitionBuilder.rootBeanDefinition(ExpressionBasedFilterInvocationSecurityMetadataSource.class); //通过构造函数注入依赖 fidsBuilder.addConstructorArgValue(matcher); fidsBuilder.addConstructorArgValue(requestToAttributesMap); fidsBuilder.addConstructorArgReference(expressionHandlerRef); } else { //定义非表达式类型的FilterInvocationSecurityMetadataSource fidsBuilder = BeanDefinitionBuilder.rootBeanDefinition(DefaultFilterInvocationSecurityMetadataSource.class); //通过构造函数注入依赖 fidsBuilder.addConstructorArgValue(matcher); fidsBuilder.addConstructorArgValue(requestToAttributesMap); } fidsBuilder.addPropertyValue("stripQueryStringFromUrls", matcher instanceof AntUrlPathMatcher); fidsBuilder.getRawBeanDefinition().setSource(pc.extractSource(elt)); return fidsBuilder.getBeanDefinition(); }
通过以上的bean构造过程,FilterSecurityInterceptor所依赖的决策管理器、认证管理器、安全元数据资源都具备了,该让FilterSecurityInterceptor干活了,其源码为
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { //封装request, response, chain,方便参数传递、增加代码阅读性 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) { if (fi.getRequest() != null) { fi.getRequest().setAttribute(FILTER_APPLIED, Boolean.TRUE); } //执行父类beforeInvocation,类似于aop中的before InterceptorStatusToken token = super.beforeInvocation(fi); try { //filter传递 fi.getChain().doFilter(fi.getRequest(), fi.getResponse()); } finally { //执行父类的afterInvocation,类似于aop中的after super.afterInvocation(token, null); } } }
继续看父类的beforeInvocation方法,其中省略了一些不重要的代码片段
protected InterceptorStatusToken beforeInvocation(Object object) { //根据SecurityMetadataSource获取配置的权限属性 Collection<ConfigAttribute> attributes = this.obtainSecurityMetadataSource().getAttributes(object); //省略…… //判断是否需要对认证实体重新认证,默认为否 Authentication authenticated = authenticateIfRequired(); // Attempt authorization try { //决策管理器开始决定是否授权,如果授权失败,直接抛出AccessDeniedException this.accessDecisionManager.decide(authenticated, object, attributes); } catch (AccessDeniedException accessDeniedException) { publishEvent(new AuthorizationFailureEvent(object, attributes, authenticated, accessDeniedException)); throw accessDeniedException; } }
增加说明
Collection<ConfigAttribute> attributes = this.obtainSecurityMetadataSource().getAttributes(object);
这里获取的是权限列表信息,比如说有这个配置
<security:intercept-url pattern="/index.jsp*" access="ROLE_USER,ROLE_ADMIN"/>
如果现在发起一个请求时index.jsp,那么根据这个请求返回的attributes集合就是分别包含ROLE_USER,ROLE_ADMIN属性的两个SecurityConfig对象
至于请求url如何匹配的,大家可以通过阅读DefaultFilterInvocationSecurityMetadataSource类的源码,实际上,这里用到了spring的路径匹配工具类org.springframework.util.AntPathMatcher
AntPathMatcher匹配方式的通配符有三种:
?(匹配任何单字符),*(匹配0或者任意数量的字符),**(匹配0或者更多的目录)
由于之前在bean的定义过程已经知道决策管理器是AffirmativeBased,接着看AffirmativeBased的决策过程
public void decide(Authentication authentication, Object object, Collection<ConfigAttribute> configAttributes) throws AccessDeniedException { int deny = 0; //循环voters,实际上是RoleVoter、AuthenticatedVoter for (AccessDecisionVoter voter : getDecisionVoters()) { //把具体的决策任务交给voter处理 //voter只返回-1、0、1,只有为1才算授权成功 int result = voter.vote(authentication, object, configAttributes); if (logger.isDebugEnabled()) { logger.debug("Voter: " + voter + ", returned: " + result); } switch (result) { case AccessDecisionVoter.ACCESS_GRANTED: return; case AccessDecisionVoter.ACCESS_DENIED: deny++; break; default: break; } } //只要有一个voter拒绝了,则直接抛出访问拒绝异常 if (deny > 0) { throw new AccessDeniedException(messages.getMessage("AbstractAccessDecisionManager.accessDenied", "Access is denied")); } // To get this far, every AccessDecisionVoter abstained checkAllowIfAllAbstainDecisions(); }
实际上,有三种决策管理器,分别为AffirmativeBased、ConsensusBased、UnanimousBased,各自决策的区别是:
AffirmativeBased:只要有一个voter投同意票,就授权成功
ConsensusBased:只要投同意票的大于投反对票的,就授权成功
UnanimousBased:需要一致通过才授权成功具体决策规则很简单,只是根据voter返回的结果做处理
接下来,分别看RoleVoter、AuthenticatedVoter的源码
RoleVoter:
public int vote(Authentication authentication, Object object, Collection<ConfigAttribute> attributes) { int result = ACCESS_ABSTAIN; //从认证实体中获取所有的权限列表 Collection<GrantedAuthority> authorities = extractAuthorities(authentication); //循环intercept-url配置的access权限列表 for (ConfigAttribute attribute : attributes) { if (this.supports(attribute)) { result = ACCESS_DENIED; // Attempt to find a matching granted authority //循环认证实体所拥有的权限列表 for (GrantedAuthority authority : authorities) { if (attribute.getAttribute().equals(authority.getAuthority())) { //只要有相同的权限,直接返回成功1 return ACCESS_GRANTED; } } } } return result; }
AuthenticatedVoter:
public int vote(Authentication authentication, Object object, Collection<ConfigAttribute> attributes) { int result = ACCESS_ABSTAIN; for (ConfigAttribute attribute : attributes) { if (this.supports(attribute)) { result = ACCESS_DENIED; if (IS_AUTHENTICATED_FULLY.equals(attribute.getAttribute())) { if (isFullyAuthenticated(authentication)) { return ACCESS_GRANTED; } } if (IS_AUTHENTICATED_REMEMBERED.equals(attribute.getAttribute())) { if (authenticationTrustResolver.isRememberMe(authentication) || isFullyAuthenticated(authentication)) { return ACCESS_GRANTED; } } if (IS_AUTHENTICATED_ANONYMOUSLY.equals(attribute.getAttribute())) { if (authenticationTrustResolver.isAnonymous(authentication) || isFullyAuthenticated(authentication) || authenticationTrustResolver.isRememberMe(authentication)) { return ACCESS_GRANTED; } } } } return result; }
由于RoleVoter在list列表中的位置处于AuthenticatedVoter前面,只要RoleVoter通过,就不会再执行AuthenticatedVoter了。实际上AuthenticatedVoter只会对IS_AUTHENTICATED_FULLY、IS_AUTHENTICATED_REMEMBERED、IS_AUTHENTICATED_ANONYMOUSLY三种权限做vote处理。
评论
1 楼
wangzhiwei231
2015-09-30
有一个疑问 authenticationManager作为认证管理器 在认证和授权的过程中 作用是不是和UsernamepasswordAutenticationFilter里面的authenticationManager 是一样的 那如果有了filterSecurityInterceptor 可否直接省略登录时候的验证
发表评论
-
Spring Security3源码分析-电子书下载
2012-07-30 14:34 8544提供电子书下载链接。 -
Spring Security3源码分析-CAS支持
2012-05-13 21:03 25773Spring Security3对CAS的支持主要在这个spr ... -
Spring Security3源码分析-SSL支持
2012-05-10 12:48 11072Sping Security3对于SSL的支持仅仅表现在对需要 ... -
Spring Security3源码分析-认证授权分析
2012-05-09 21:59 6361前面分析了FilterChainProxy执行过程,也对常用的 ... -
Spring Security3源码分析-Filter链排序分析
2012-05-09 14:39 15297通过前面Spring Security提供的各种Filter的 ... -
Spring Security3源码分析-RequestCacheAwareFilter分析
2012-05-09 12:55 4878RequestCacheAwareFilter过滤器对应的类路 ... -
Spring Security3源码分析-ExceptionTranslationFilter分析
2012-05-09 10:03 7802ExceptionTranslationFilter过滤器对应 ... -
Spring Security3源码分析-SessionManagementFilter分析-下
2012-05-08 21:03 6336很多spring security3资料在 ... -
Spring Security3源码分析-SessionManagementFilter分析-上
2012-05-08 17:26 10918SessionManagementFilter过滤 ... -
Spring Security3源码分析-AnonymousAuthenticationFilter分析
2012-05-08 10:32 5194AnonymousAuthenticationFilter ... -
Spring Security3源码分析-BasicAuthenticationFilter分析
2012-05-08 09:24 9602BasicAuthenticationFilter过滤器对应的 ... -
Spring Security3源码分析-SecurityContextHolderAwareRequestFilter分析
2012-05-07 10:34 6817SecurityContextHolderAwareReque ... -
Spring Security3源码分析-RememberMeAuthenticationFilter分析
2012-05-06 22:33 5945RememberMeAuthenticationFilter过 ... -
Spring Security3源码分析-UsernamePasswordAuthenticationFilter分析
2012-05-06 11:54 24859UsernamePasswordAuthenticationF ... -
Spring Security3源码分析-LogoutFilter分析
2012-05-06 10:18 10295LogoutFilter过滤器对应的类路径为 org.spri ... -
Spring Security3源码分析-SecurityContextPersistenceFilter分析
2012-05-06 08:22 8723通过观察Filter的名字,就能大概猜出来这个过滤器的作用,是 ... -
Spring Security3源码分析-FilterChainProxy执行过程分析
2012-05-06 07:48 4241通过FilterChainProxy的初始化、自定义标签的分析 ... -
Spring Security3源码分析-authentication-manager标签解析
2012-05-05 16:13 21678讲解完http标签的解析过程,authentication-m ... -
Spring Security3源码分析-http标签解析
2012-05-05 15:29 8436在FilterChainProxy初始化的 ... -
Spring Security3源码分析-FilterChainProxy初始化
2012-05-04 16:57 20047很久没有更新博客了,最近对Spring Security做了比 ...
相关推荐
SpringSecurity-with-SpringBoot 使用Spring Security进行表单身份验证。根据权限而不是角色进行检查。 应用程式运动 访问本地主机:8080 / rbac / 以初始用户身份登录 管理员可以更改与角色关联的权限 再次登录时...
Spring Security-3.0.1 中文官方文档(翻译版) 这次发布的Spring Security-3.0.1 是一个bug fix 版,主要是对3.0 中存在的一些问题进 行修 正。文档中没有添加新功能的介绍,但是将之前拼写错误的一些类名进行...
主要介绍了Spring security用户URL权限FilterSecurityInterceptor使用解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
3. Spring Security 4.2的新特性 27 3.1 Web改进 27 3.2配置改进 28 3.3杂项 28 4.样品和指南(从这里开始) 28 5. Java配置 29 5.1 Hello Web安全Java配置 29 5.1.1 AbstractSecurityWebApplicationInitializer 31 ...
那么在Spring Security3的使用中,有4种方法: 一种是全部利用配置文件,将用户、权限、资源(url)硬编码在xml文件中,已经实现过,并经过验证; 二种是用户和权限用数据库存储,而资源(url)和权限的对应采用硬编码...
1.1. Spring Security是什么? 1.2. 历史 1.3. 发行版本号 1.4. 获得Spring Security 1.4.1. 项目模块 1.4.1.1. Core - spring-security-core.jar 1.4.1.2. Web - spring-security-web.jar 1.4.1.3. Config -...
Spring Security3的使用方法有4种: 一种是全部利用配置文件,将用户、权限、资源(url)硬编码在xml文件中。 二种是用户和权限用数据库存储,而资源(url)和权限的对应采用硬编码配置。 三种是细分角色和权限,并将...
1.1. Spring Security是什么? 1.2. 历史 1.3. 发行版本号 1.4. 获得Spring Security 1.4.1. 项目模块 1.4.1.1. Core - spring-security-core.jar 1.4.1.2. Web - spring-security-web.jar 1.4.1.3. ...
一种是全部利用配置文件,将用户、权限、...三种是细分角色和权限,并将用户、角色、权限和资源均采用数据库存储,并且自定义过滤器,代替原有的FilterSecurityInterceptor过滤器,并分别实现AccessDecisionManager、
word源码java Word Ladder with authenticating user 1. 实现spring security的四种方法 ...security源码 修改InvocationSecurityMetadataSourceService和UserDetailsService两个类。 前者是将配置文件或数
Security 有两种认证方式: ...formLogin 默认的,如上边那种方式 ...图中橙色的 FilterSecurityInterceptor 是最终的过滤器,它会决定当前的请求可不可以访问Controller,判断规则放在这个里面。
FilterSecurityInterceptor 中的doFilter->invoke方法 //看有没有权限 获取遍历 antMatchers中的url有的话标记为不用授权 AbstractSecurityInterceptor 中Collection<ConfigAttribute> attributes = this....
Acegi认证授权主要基于两大技术...通过FilterSecurityInterceptor很好地实现 了对URI的保护,通过MethodSecurityInterceptor实现了对Service的方法的拦截保护,通过ACL 实现了对prototype类型的Object进行过滤和保护。