【Spring-Security源码分析】Spring Security基于注解认证原理

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/shenchaohao12321/article/details/87973800

1、开启注解功能

Spring Security默认是禁用注解的,要想开启注解功能需要在@Configuration类上加入@EnableMethodSecurity注解来判断用户对某个控制层的方法是否具有访问权限。

@Configuration
@EnableGlobalMethodSecurity(prePostEnabled =true)
public class WebSecurityConfigextends WebSecurityConfigurerAdapter {……}

@EnableGlobalMethodSecurity属性说明:

  • prePostEnabled: 确定是否应启用Spring Security的预发布注释。
  • securedEnabled:确定是否应启用Spring Security的@Secured 注解。
  • jsr250Enabled:确定是否应启用JSR-250注释。 

2、主要的bean

@Import({ GlobalMethodSecuritySelector.class })
@EnableGlobalAuthentication
@Configuration
public @interface EnableGlobalMethodSecurity {
...
}

可以看到@EnableGlobalMethodSecurity引入了一个@EnableGlobalAuthentication注解,这个注解我之前分析过了主要是引入了一个Spring容器提供的AuthenticationManager,详情请参考【Spring-Security源码分析】Spring Security启动过程。这里主要关注GlobalMethodSecuritySelector。

final class GlobalMethodSecuritySelector implements ImportSelector {
   public final String[] selectImports(AnnotationMetadata importingClassMetadata) {
      Class<EnableGlobalMethodSecurity> annoType = EnableGlobalMethodSecurity.class;
      Map<String, Object> annotationAttributes = importingClassMetadata
            .getAnnotationAttributes(annoType.getName(), false);
      AnnotationAttributes attributes = AnnotationAttributes
            .fromMap(annotationAttributes);
      Assert.notNull(attributes, () -> String.format(
            "@%s is not present on importing class '%s' as expected",
            annoType.getSimpleName(), importingClassMetadata.getClassName()));
      // TODO would be nice if could use BeanClassLoaderAware (does not work)
      Class<?> importingClass = ClassUtils
            .resolveClassName(importingClassMetadata.getClassName(),
                  ClassUtils.getDefaultClassLoader());
      boolean skipMethodSecurityConfiguration = GlobalMethodSecurityConfiguration.class
            .isAssignableFrom(importingClass);
      AdviceMode mode = attributes.getEnum("mode");
      boolean isProxy = AdviceMode.PROXY == mode;
      String autoProxyClassName = isProxy ? AutoProxyRegistrar.class
            .getName() : GlobalMethodSecurityAspectJAutoProxyRegistrar.class
            .getName();
      boolean jsr250Enabled = attributes.getBoolean("jsr250Enabled");
      List<String> classNames = new ArrayList<>(4);
      if (isProxy) {
      //用于拦截权限注解方法
         classNames.add(MethodSecurityMetadataSourceAdvisorRegistrar.class.getName());
      }
      classNames.add(autoProxyClassName);
      if (!skipMethodSecurityConfiguration) {
         //通过MethodSecurityMetadataSourceAdvisorRegistrar注册的bean需要的构造参数定义在这里
         classNames.add(GlobalMethodSecurityConfiguration.class.getName());
      }
      //jsr250的支持
      if (jsr250Enabled) {
         classNames.add(Jsr250MetadataSourceConfiguration.class.getName());
      }
      return classNames.toArray(new String[0]);
   }
}

2.1、MethodSecurityMetadataSourceAdvisor的创建

上面代码返回一个MethodSecurityMetadataSourceAdvisorRegistrar,这个类会向Spring容器注册一个MethodSecurityMetadataSourceAdvisor。

class MethodSecurityMetadataSourceAdvisorRegistrar implements
      ImportBeanDefinitionRegistrar {

   public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata,
         BeanDefinitionRegistry registry) {
      BeanDefinitionBuilder advisor = BeanDefinitionBuilder
            .rootBeanDefinition(MethodSecurityMetadataSourceAdvisor.class);
      advisor.setRole(BeanDefinition.ROLE_INFRASTRUCTURE);
      advisor.addConstructorArgValue("methodSecurityInterceptor");
      advisor.addConstructorArgReference("methodSecurityMetadataSource");
      advisor.addConstructorArgValue("methodSecurityMetadataSource");
      MultiValueMap<String, Object> attributes = importingClassMetadata.getAllAnnotationAttributes(EnableGlobalMethodSecurity.class.getName());
      Integer order = (Integer) attributes.getFirst("order");
      if (order != null) {
         advisor.addPropertyValue("order", order);
      }

      registry.registerBeanDefinition("metaDataSourceAdvisor",
            advisor.getBeanDefinition());
   }
}

MethodSecurityMetadataSourceAdvisor构造函数需要的三个参数,methodSecurityInterceptor(一个拦截器的bean name)、methodSecurityMetadataSource(Spring容器定义的bean)、methodSecurityMetadataSource(前者的bean name)定义在GlobalMethodSecurityConfiguration,我们稍后再看。

这里我们主要关注MethodSecurityMetadataSourceAdvisor会拦截哪些方法和持有的Advice。

MethodSecurityMetadataSourceAdvisor的getPointcut()返回的Pointcut是一个MethodSecurityMetadataSourcePointcut,具体拦截行为如下:

class MethodSecurityMetadataSourcePointcut extends StaticMethodMatcherPointcut
      implements Serializable {
   @SuppressWarnings("unchecked")
   public boolean matches(Method m, Class targetClass) {
      //attributeSource是MethodSecurityMetadataSourceAdvisor构造方法传入的MethodSecurityMetadataSource实例
      Collection attributes = attributeSource.getAttributes(m, targetClass);
      return attributes != null && !attributes.isEmpty();
   }
}

getAdvice()方法返回的是从Spring容器中获取名为methodSecurityInterceptor的MethodInterceptor,所以我们只要弄明白了Spring容器中提供的methodSecurityInterceptor和methodSecurityMetadataSource,就清楚了基于注解权限验证的原理。

2.2、methodSecurityInterceptor和methodSecurityMetadataSource的定义

这两个重要的bean定义在GlobalMethodSecurityConfiguration中。

2.2.1、DelegatingMethodSecurityMetadataSource

@Bean
public MethodSecurityMetadataSource methodSecurityMetadataSource() {
   List<MethodSecurityMetadataSource> sources = new ArrayList<>();
   //为PrePostAnnotationSecurityMetadataSource服务,提到它时再说
   ExpressionBasedAnnotationAttributeFactory attributeFactory = new ExpressionBasedAnnotationAttributeFactory(
         getExpressionHandler());
   MethodSecurityMetadataSource customMethodSecurityMetadataSource = customMethodSecurityMetadataSource();
   if (customMethodSecurityMetadataSource != null) {
      sources.add(customMethodSecurityMetadataSource);
   }
   //可以自定义customMethodSecurityMetadataSource
   boolean hasCustom = customMethodSecurityMetadataSource != null;
   boolean isPrePostEnabled = prePostEnabled();
   boolean isSecuredEnabled = securedEnabled();
   boolean isJsr250Enabled = jsr250Enabled();
   //支持的注解都没开启就没必要开启了
   if (!isPrePostEnabled && !isSecuredEnabled && !isJsr250Enabled && !hasCustom) {
      throw new IllegalStateException("In the composition of all global method configuration, " +
            "no annotation support was actually activated");
   }
   if (isPrePostEnabled) {
      sources.add(new PrePostAnnotationSecurityMetadataSource(attributeFactory));
   }
   if (isSecuredEnabled) {
      sources.add(new SecuredAnnotationSecurityMetadataSource());
   }
   if (isJsr250Enabled) {
      GrantedAuthorityDefaults grantedAuthorityDefaults =
            getSingleBeanOrNull(GrantedAuthorityDefaults.class);
      Jsr250MethodSecurityMetadataSource jsr250MethodSecurityMetadataSource = this.context.getBean(Jsr250MethodSecurityMetadataSource.class);
      if (grantedAuthorityDefaults != null) {
         jsr250MethodSecurityMetadataSource.setDefaultRolePrefix(
               grantedAuthorityDefaults.getRolePrefix());
      }
      sources.add(jsr250MethodSecurityMetadataSource);
   }
   return new DelegatingMethodSecurityMetadataSource(sources);
}

这里定义了一个DelegatingMethodSecurityMetadataSource它是PrePostAnnotationSecurityMetadataSource、SecuredAnnotationSecurityMetadataSource、Jsr250MethodSecurityMetadataSource的组合。这个bean是为MethodSecurityInterceptor提供ConfigAttribute的。

2.2.1、MethodSecurityInterceptor

@Bean
public MethodInterceptor methodSecurityInterceptor() throws Exception {
   this.methodSecurityInterceptor = isAspectJ()
         ? new AspectJMethodSecurityInterceptor()
         : new MethodSecurityInterceptor();
   methodSecurityInterceptor.setAccessDecisionManager(accessDecisionManager());
   methodSecurityInterceptor.setAfterInvocationManager(afterInvocationManager());
   methodSecurityInterceptor
         .setSecurityMetadataSource(methodSecurityMetadataSource());
   RunAsManager runAsManager = runAsManager();
   if (runAsManager != null) {
      methodSecurityInterceptor.setRunAsManager(runAsManager);
   }
   return this.methodSecurityInterceptor;
}

MethodSecurityInterceptor的invoke()方法的拦截功能实现委托给了父类的beforeInvocation()、finallyInvocation()、afterInvocation()方法,在《【Spring-Security源码分析】WebSecurity》我们分析过AbstractSecurityInterceptor的实现可知beforeInvocation()中是通过accessDecisionManager的decide()方法检查权限,执行完目标方法后在afterInvocation()方法中通过afterInvocationManager的decide()的方法再次检查权限。

accessDecisionManager是一个持有PreInvocationAuthorizationAdviceVoter、Jsr250Voter、RoleVoter、AuthenticatedVoter的AffirmativeBased。

protected AccessDecisionManager accessDecisionManager() {
   List<AccessDecisionVoter<? extends Object>> decisionVoters = new ArrayList<AccessDecisionVoter<? extends Object>>();
   ExpressionBasedPreInvocationAdvice expressionAdvice = new ExpressionBasedPreInvocationAdvice();
   expressionAdvice.setExpressionHandler(getExpressionHandler());
   if (prePostEnabled()) {
      decisionVoters
            .add(new PreInvocationAuthorizationAdviceVoter(expressionAdvice));
   }
   if (jsr250Enabled()) {
      decisionVoters.add(new Jsr250Voter());
   }
   decisionVoters.add(new RoleVoter());
   decisionVoters.add(new AuthenticatedVoter());
   return new AffirmativeBased(decisionVoters);
}

afterInvocationManager是内部使用PostInvocationAuthorizationAdvice完成集合的过滤(如果目标方法返回的是集合)和再次权限的验证。

protected AfterInvocationManager afterInvocationManager() {
   if (prePostEnabled()) {
      AfterInvocationProviderManager invocationProviderManager = new AfterInvocationProviderManager();
      ExpressionBasedPostInvocationAdvice postAdvice = new ExpressionBasedPostInvocationAdvice(
            getExpressionHandler());
      PostInvocationAdviceProvider postInvocationAdviceProvider = new PostInvocationAdviceProvider(
            postAdvice);
      List<AfterInvocationProvider> afterInvocationProviders = new ArrayList<>();
      afterInvocationProviders.add(postInvocationAdviceProvider);
      invocationProviderManager.setProviders(afterInvocationProviders);
      return invocationProviderManager;
   }
   return null;
}

我们先从accessDecisionManager的实现开始分析,它内部有4种AccessDecisionVoter,不同的AccessDecisionVoter负责处理不同ConfigAttribute的类型通过supports()方法。

先看PreInvocationAuthorizationAdviceVoter的supports()方法。

public boolean supports(ConfigAttribute attribute) {
   return attribute instanceof PreInvocationAttribute;
}

它支持PreInvocationAttribute这种ConfigAttribute的投票,那PreInvocationAttribute是怎么来了呢

在AbstractSecurityInterceptor#beforeInvocation()方法被调用时会使用MethodSecurityInterceptor持有的DelegatingMethodSecurityMetadataSource取得与目标对象相关联的ConfigAttribute集合传给accessDecisionManager完成授权。还记得上面讲过DelegatingMethodSecurityMetadataSource是多个SecurityMetadataSource的组合吗,其中就存在PrePostAnnotationSecurityMetadataSource用来根据方法上的注解@PreFilter、@PreAuthorize和@PostFilter、PostAuthorize生成PreInvocationAttribute和PostInvocationAttribute。

PrePostAnnotationSecurityMetadataSource概述

MethodSecurityMetadataSource,用于从放置在方法上的@PreFilter和@PreAuthorize注释中提取元数据。 该类仅负责查找相关注释(如果有)。 它将实际的ConfigAttribute创建委托给其PrePostInvocationAttributeFactory,从而将自身与将强制注释行为的机制分离。
可以在类或方法上指定注释,并且特定于方法的注释优先。 如果您使用任何注释并且未指定预授权条件,则将允许该方法,就像存在@PreAuthorize(“permitAll”)一样。
由于我们在这里处理多个注释,因此我们可能必须将在多个位置定义的注释组合为单个方法 - 它们可以在方法本身上定义,也可以在接口或类级别定义。

PrePostAnnotationSecurityMetadataSource的getAttributes(Object object)定义在父类AbstractMethodSecurityMetadataSource中,

public abstract class AbstractMethodSecurityMetadataSource implements
      MethodSecurityMetadataSource {
   protected final Log logger = LogFactory.getLog(getClass());
   public final Collection<ConfigAttribute> getAttributes(Object object) {
      if (object instanceof MethodInvocation) {
         MethodInvocation mi = (MethodInvocation) object;
         Object target = mi.getThis();
         Class<?> targetClass = null;

         if (target != null) {
            targetClass = target instanceof Class<?> ? (Class<?>) target
                  : AopProxyUtils.ultimateTargetClass(target);
         }
         Collection<ConfigAttribute> attrs = getAttributes(mi.getMethod(), targetClass);
         if (attrs != null && !attrs.isEmpty()) {
            return attrs;
         }
         if (target != null && !(target instanceof Class<?>)) {
            attrs = getAttributes(mi.getMethod(), target.getClass());
         }
         return attrs;
      }
      throw new IllegalArgumentException("Object must be a non-null MethodInvocation");
   }
   public final boolean supports(Class<?> clazz) {
      return (MethodInvocation.class.isAssignableFrom(clazz));
   }
}

子类实现getAttributes(Method method, Class<?> targetClass)方法。

public Collection<ConfigAttribute> getAttributes(Method method, Class<?> targetClass) {
   if (method.getDeclaringClass() == Object.class) {
      return Collections.emptyList();
   }
   logger.trace("Looking for Pre/Post annotations for method '" + method.getName()
         + "' on target class '" + targetClass + "'");
   PreFilter preFilter = findAnnotation(method, targetClass, PreFilter.class);
   PreAuthorize preAuthorize = findAnnotation(method, targetClass,
         PreAuthorize.class);
   PostFilter postFilter = findAnnotation(method, targetClass, PostFilter.class);
   // TODO: Can we check for void methods and throw an exception here?
   PostAuthorize postAuthorize = findAnnotation(method, targetClass,
         PostAuthorize.class);
   if (preFilter == null && preAuthorize == null && postFilter == null
         && postAuthorize == null) {
      // There is no meta-data so return
      logger.trace("No expression annotations found");
      return Collections.emptyList();
   }
   String preFilterAttribute = preFilter == null ? null : preFilter.value();
   String filterObject = preFilter == null ? null : preFilter.filterTarget();
   String preAuthorizeAttribute = preAuthorize == null ? null : preAuthorize.value();
   String postFilterAttribute = postFilter == null ? null : postFilter.value();
   String postAuthorizeAttribute = postAuthorize == null ? null : postAuthorize
         .value();
   ArrayList<ConfigAttribute> attrs = new ArrayList<>(2);
   PreInvocationAttribute pre = attributeFactory.createPreInvocationAttribute(
         preFilterAttribute, filterObject, preAuthorizeAttribute);
   if (pre != null) {
      attrs.add(pre);
   }
   PostInvocationAttribute post = attributeFactory.createPostInvocationAttribute(
         postFilterAttribute, postAuthorizeAttribute);
   if (post != null) {
      attrs.add(post);
   }
   attrs.trimToSize();
   return attrs;
}

PreInvocationAttribute和PostInvocationAttribute的创建分别使用ExpressionBasedAnnotationAttributeFactory的createPreInvocationAttribute()和createPostInvocationAttribute()。

public class ExpressionBasedAnnotationAttributeFactory implements
      PrePostInvocationAttributeFactory {
   private final Object parserLock = new Object();
   private ExpressionParser parser;
   private MethodSecurityExpressionHandler handler;
   public ExpressionBasedAnnotationAttributeFactory(
         MethodSecurityExpressionHandler handler) {
      this.handler = handler;
   }
   public PreInvocationAttribute createPreInvocationAttribute(String preFilterAttribute,
         String filterObject, String preAuthorizeAttribute) {
      try {
         // TODO: Optimization of permitAll
         ExpressionParser parser = getParser();
         Expression preAuthorizeExpression = preAuthorizeAttribute == null ? parser
               .parseExpression("permitAll") : parser
               .parseExpression(preAuthorizeAttribute);
         Expression preFilterExpression = preFilterAttribute == null ? null : parser
               .parseExpression(preFilterAttribute);
         return new PreInvocationExpressionAttribute(preFilterExpression,
               filterObject, preAuthorizeExpression);
      }
      catch (ParseException e) {
         throw new IllegalArgumentException("Failed to parse expression '"
               + e.getExpressionString() + "'", e);
      }
   }

   public PostInvocationAttribute createPostInvocationAttribute(
         String postFilterAttribute, String postAuthorizeAttribute) {
      try {
         ExpressionParser parser = getParser();
         Expression postAuthorizeExpression = postAuthorizeAttribute == null ? null
               : parser.parseExpression(postAuthorizeAttribute);
         Expression postFilterExpression = postFilterAttribute == null ? null : parser
               .parseExpression(postFilterAttribute);

         if (postFilterExpression != null || postAuthorizeExpression != null) {
            return new PostInvocationExpressionAttribute(postFilterExpression,
                  postAuthorizeExpression);
         }
      }
      catch (ParseException e) {
         throw new IllegalArgumentException("Failed to parse expression '"
               + e.getExpressionString() + "'", e);
      }

      return null;
   }
   private ExpressionParser getParser() {
      if (this.parser != null) {
         return this.parser;
      }
      synchronized (parserLock) {
         this.parser = handler.getExpressionParser();
         this.handler = null;
      }
      return this.parser;
   }
}

关于Expression的求值过程请参考《【Spring-Security源码分析】Spring安全表达式解析》

知道了PreInvocationAttribute的获取过程下面分析PreInvocationAuthorizationAdviceVoter的vote()方法实现。

public int vote(Authentication authentication, MethodInvocation method,
      Collection<ConfigAttribute> attributes) {
   //查找prefilter和preauth(或组合)属性如果两者都为null,则禁止访问
   PreInvocationAttribute preAttr = findPreInvocationAttribute(attributes);
   if (preAttr == null) {
      // No expression based metadata, so abstain
      return ACCESS_ABSTAIN;
   }
   boolean allowed = preAdvice.before(authentication, method, preAttr);
   return allowed ? ACCESS_GRANTED : ACCESS_DENIED;
}

ExpressionBasedPreInvocationAdvice#before()方法实现。

public boolean before(Authentication authentication, MethodInvocation mi,
      PreInvocationAttribute attr) {
   PreInvocationExpressionAttribute preAttr = (PreInvocationExpressionAttribute) attr;
   EvaluationContext ctx = expressionHandler.createEvaluationContext(authentication,
         mi);
   Expression preFilter = preAttr.getFilterExpression();
   Expression preAuthorize = preAttr.getAuthorizeExpression();

   if (preFilter != null) {
      Object filterTarget = findFilterTarget(preAttr.getFilterTarget(), ctx, mi);
      expressionHandler.filter(filterTarget, preFilter, ctx);
   }
   if (preAuthorize == null) {
      return true;
   }
   return ExpressionUtils.evaluateAsBoolean(preAuthorize, ctx);
}

private Object findFilterTarget(String filterTargetName, EvaluationContext ctx,
      MethodInvocation mi) {
   Object filterTarget = null;
   if (filterTargetName.length() > 0) {
      filterTarget = ctx.lookupVariable(filterTargetName);
      if (filterTarget == null) {
         throw new IllegalArgumentException(
               "Filter target was null, or no argument with name "
                     + filterTargetName + " found in method");
      }
   }
   else if (mi.getArguments().length == 1) {
      Object arg = mi.getArguments()[0];
      if (arg.getClass().isArray() || arg instanceof Collection<?>) {
         filterTarget = arg;
      }
      if (filterTarget == null) {
         throw new IllegalArgumentException(
               "A PreFilter expression was set but the method argument type"
                     + arg.getClass() + " is not filterable");
      }
   }
   if (filterTarget.getClass().isArray()) {
      throw new IllegalArgumentException(
            "Pre-filtering on array types is not supported. "
                  + "Using a Collection will solve this problem");
   }
   return filterTarget;
}

在上面before()方法中除了权限检查外还可以完成对@PreFilter filterTarger指定的EvaluationContext中的属性集合属性进行过滤,通过下面DefaultMethodSecurityExpressionHandler的filter()方法可知,此filterTarget属性对象的表达式必须为"filterObject"。

//通过评估提供的表达式过滤filterTarget对象(必须是集合或数组)。
//如果使用Collection,则将修改原始实例以包含权限表达式求值为true的元素。 对于数组,将返回新的数组实例。
public Object filter(Object filterTarget, Expression filterExpression,
      EvaluationContext ctx) {
   MethodSecurityExpressionOperations rootObject = (MethodSecurityExpressionOperations) ctx
         .getRootObject().getValue();
   final boolean debug = logger.isDebugEnabled();
   List retainList;
   if (debug) {
      logger.debug("Filtering with expression: "
            + filterExpression.getExpressionString());
   }
   if (filterTarget instanceof Collection) {
      Collection collection = (Collection) filterTarget;
      retainList = new ArrayList(collection.size());
      if (debug) {
         logger.debug("Filtering collection with " + collection.size()
               + " elements");
      }
      if (permissionCacheOptimizer != null) {
         permissionCacheOptimizer.cachePermissionsFor(
               rootObject.getAuthentication(), collection);
      }
      for (Object filterObject : (Collection) filterTarget) {
         //从这里可以看出是针对根对象的filterObject属性过滤的
         rootObject.setFilterObject(filterObject);
         if (ExpressionUtils.evaluateAsBoolean(filterExpression, ctx)) {
            retainList.add(filterObject);
         }
      }
      if (debug) {
         logger.debug("Retaining elements: " + retainList);
      }
      collection.clear();
      collection.addAll(retainList);
      return filterTarget;
   }
   if (filterTarget.getClass().isArray()) {
      Object[] array = (Object[]) filterTarget;
      retainList = new ArrayList(array.length);
      if (debug) {
         logger.debug("Filtering array with " + array.length + " elements");
      }
      if (permissionCacheOptimizer != null) {
         permissionCacheOptimizer.cachePermissionsFor(
               rootObject.getAuthentication(), Arrays.asList(array));
      }
      for (Object o : array) {
         rootObject.setFilterObject(o);
         if (ExpressionUtils.evaluateAsBoolean(filterExpression, ctx)) {
            retainList.add(o);
         }
      }
      if (debug) {
         logger.debug("Retaining elements: " + retainList);
      }
      Object[] filtered = (Object[]) Array.newInstance(filterTarget.getClass()
            .getComponentType(), retainList.size());
      for (int i = 0; i < retainList.size(); i++) {
         filtered[i] = retainList.get(i);
      }
      return filtered;
   }
   throw new IllegalArgumentException(
         "Filter target must be a collection or array type, but was "
               + filterTarget);
}

PostInvocationAuthorizationAdvice用于调用目标方法后的验证。

public class ExpressionBasedPostInvocationAdvice implements
      PostInvocationAuthorizationAdvice {
   protected final Log logger = LogFactory.getLog(getClass());
   private final MethodSecurityExpressionHandler expressionHandler;
   public ExpressionBasedPostInvocationAdvice(
         MethodSecurityExpressionHandler expressionHandler) {
      this.expressionHandler = expressionHandler;
   }
   public Object after(Authentication authentication, MethodInvocation mi,
         PostInvocationAttribute postAttr, Object returnedObject)
         throws AccessDeniedException {
      PostInvocationExpressionAttribute pia = (PostInvocationExpressionAttribute) postAttr;
      EvaluationContext ctx = expressionHandler.createEvaluationContext(authentication,
            mi);
      Expression postFilter = pia.getFilterExpression();
      Expression postAuthorize = pia.getAuthorizeExpression();

      if (postFilter != null) {
         if (logger.isDebugEnabled()) {
            logger.debug("Applying PostFilter expression " + postFilter);
         }
         //过滤的是返回的集合对象
         if (returnedObject != null) {
            returnedObject = expressionHandler
                  .filter(returnedObject, postFilter, ctx);
         }
         else {
            if (logger.isDebugEnabled()) {
               logger.debug("Return object is null, filtering will be skipped");
            }
         }
      }
      //验证规则可针对returnObject
      expressionHandler.setReturnObject(returnedObject, ctx);
      if (postAuthorize != null
            && !ExpressionUtils.evaluateAsBoolean(postAuthorize, ctx)) {
         if (logger.isDebugEnabled()) {
            logger.debug("PostAuthorize expression rejected access");
         }
         throw new AccessDeniedException("Access is denied");
      }
      return returnedObject;
   }
}

猜你喜欢

转载自blog.csdn.net/shenchaohao12321/article/details/87973800
今日推荐