FilterSecurityInterceptor过滤器对应的类路径为
org.springframework.security.web.access.intercept.FilterSecurityInterceptor
这个filter是filterchain中比较复杂,也是比较核心的过滤器,主要负责授权的工作
在看这个filter源码之前,先来看看spring是如何构造filter这个bean的
具体的构造过程的代码片段为
-
- void createFilterSecurityInterceptor(BeanReference authManager) {
-
- boolean useExpressions = FilterInvocationSecurityMetadataSourceParser.isUseExpressions(httpElt);
-
- BeanDefinition securityMds = FilterInvocationSecurityMetadataSourceParser.createSecurityMetadataSource(interceptUrls, httpElt, pc);
-
- RootBeanDefinition accessDecisionMgr;
-
- ManagedList<BeanDefinition> voters = new ManagedList<BeanDefinition>(2);
-
-
- if (useExpressions) {
- voters.add(new RootBeanDefinition(WebExpressionVoter.class));
- } else {
- voters.add(new RootBeanDefinition(RoleVoter.class));
- voters.add(new RootBeanDefinition(AuthenticatedVoter.class));
- }
-
- accessDecisionMgr = new RootBeanDefinition(AffirmativeBased.class);
-
- accessDecisionMgr.getPropertyValues().addPropertyValue("decisionVoters", voters);
- accessDecisionMgr.setSource(pc.extractSource(httpElt));
-
-
- String accessManagerId = httpElt.getAttribute(ATT_ACCESS_MGR);
-
-
- if (!StringUtils.hasText(accessManagerId)) {
- accessManagerId = pc.getReaderContext().generateBeanName(accessDecisionMgr);
- pc.registerBeanComponent(new BeanComponentDefinition(accessDecisionMgr, accessManagerId));
- }
-
- 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();
-
- String fsiId = pc.getReaderContext().generateBeanName(fsiBean);
- pc.registerBeanComponent(new BeanComponentDefinition(fsiBean,fsiId));
-
-
- 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) {
-
- UrlMatcher matcher = HttpSecurityBeanDefinitionParser.createUrlMatcher(elt);
- boolean useExpressions = isUseExpressions(elt);
-
-
- ManagedMap<BeanDefinition, BeanDefinition> requestToAttributesMap = parseInterceptUrlsForFilterInvocationRequestMap(
- interceptUrls, useExpressions, pc);
- BeanDefinitionBuilder fidsBuilder;
-
- if (useExpressions) {
-
- 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));
- }
-
- fidsBuilder = BeanDefinitionBuilder.rootBeanDefinition(ExpressionBasedFilterInvocationSecurityMetadataSource.class);
-
- fidsBuilder.addConstructorArgValue(matcher);
- fidsBuilder.addConstructorArgValue(requestToAttributesMap);
- fidsBuilder.addConstructorArgReference(expressionHandlerRef);
- } else {
-
- 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 {
-
- 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);
- }
-
- InterceptorStatusToken token = super.beforeInvocation(fi);
-
- try {
-
- fi.getChain().doFilter(fi.getRequest(), fi.getResponse());
- } finally {
-
- super.afterInvocation(token, null);
- }
- }
- }
继续看父类的beforeInvocation方法,其中省略了一些不重要的代码片段
- protected InterceptorStatusToken beforeInvocation(Object object) {
-
- Collection<ConfigAttribute> attributes = this.obtainSecurityMetadataSource().getAttributes(object);
-
-
- Authentication authenticated = authenticateIfRequired();
-
-
- try {
-
- 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;
-
- for (AccessDecisionVoter voter : getDecisionVoters()) {
-
-
- 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;
- }
- }
-
- if (deny > 0) {
- throw new AccessDeniedException(messages.getMessage("AbstractAccessDecisionManager.accessDenied",
- "Access is denied"));
- }
-
-
- 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);
-
- for (ConfigAttribute attribute : attributes) {
- if (this.supports(attribute)) {
- result = ACCESS_DENIED;
-
-
-
- for (GrantedAuthority authority : authorities) {
- if (attribute.getAttribute().equals(authority.getAuthority())) {
-
- 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处理。
本站仅提供存储服务,所有内容均由用户发布,如发现有害或侵权内容,请
点击举报。