spring security DefaultMethodSecurityExpressionHandler 源码

  • 2022-08-13
  • 浏览 (448)

spring security DefaultMethodSecurityExpressionHandler 代码

文件路径:/core/src/main/java/org/springframework/security/access/expression/method/DefaultMethodSecurityExpressionHandler.java

/*
 * Copyright 2002-2022 the original author or authors.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      https://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package org.springframework.security.access.expression.method;

import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Supplier;
import java.util.stream.Stream;

import org.aopalliance.intercept.MethodInvocation;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import org.springframework.core.ParameterNameDiscoverer;
import org.springframework.core.log.LogMessage;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.Expression;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.security.access.PermissionCacheOptimizer;
import org.springframework.security.access.expression.AbstractSecurityExpressionHandler;
import org.springframework.security.access.expression.ExpressionUtils;
import org.springframework.security.authentication.AuthenticationTrustResolver;
import org.springframework.security.authentication.AuthenticationTrustResolverImpl;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.parameters.DefaultSecurityParameterNameDiscoverer;
import org.springframework.util.Assert;

/**
 * The standard implementation of {@code MethodSecurityExpressionHandler}.
 * <p>
 * A single instance should usually be shared amongst the beans that require expression
 * support.
 *
 * @author Luke Taylor
 * @author Evgeniy Cheban
 * @since 3.0
 */
public class DefaultMethodSecurityExpressionHandler extends AbstractSecurityExpressionHandler<MethodInvocation>
		implements MethodSecurityExpressionHandler {

	protected final Log logger = LogFactory.getLog(getClass());

	private AuthenticationTrustResolver trustResolver = new AuthenticationTrustResolverImpl();

	private ParameterNameDiscoverer parameterNameDiscoverer = new DefaultSecurityParameterNameDiscoverer();

	private PermissionCacheOptimizer permissionCacheOptimizer = null;

	private String defaultRolePrefix = "ROLE_";

	public DefaultMethodSecurityExpressionHandler() {
	}

	/**
	 * Uses a {@link MethodSecurityEvaluationContext} as the <tt>EvaluationContext</tt>
	 * implementation.
	 */
	@Override
	public StandardEvaluationContext createEvaluationContextInternal(Authentication auth, MethodInvocation mi) {
		return new MethodSecurityEvaluationContext(auth, mi, getParameterNameDiscoverer());
	}

	@Override
	public EvaluationContext createEvaluationContext(Supplier<Authentication> authentication, MethodInvocation mi) {
		MethodSecurityExpressionOperations root = createSecurityExpressionRoot(authentication, mi);
		MethodSecurityEvaluationContext ctx = new MethodSecurityEvaluationContext(root, mi,
				getParameterNameDiscoverer());
		ctx.setBeanResolver(getBeanResolver());
		return ctx;
	}

	/**
	 * Creates the root object for expression evaluation.
	 */
	@Override
	protected MethodSecurityExpressionOperations createSecurityExpressionRoot(Authentication authentication,
			MethodInvocation invocation) {
		return createSecurityExpressionRoot(() -> authentication, invocation);
	}

	private MethodSecurityExpressionOperations createSecurityExpressionRoot(Supplier<Authentication> authentication,
			MethodInvocation invocation) {
		MethodSecurityExpressionRoot root = new MethodSecurityExpressionRoot(authentication);
		root.setThis(invocation.getThis());
		root.setPermissionEvaluator(getPermissionEvaluator());
		root.setTrustResolver(getTrustResolver());
		root.setRoleHierarchy(getRoleHierarchy());
		root.setDefaultRolePrefix(getDefaultRolePrefix());
		return root;
	}

	/**
	 * Filters the {@code filterTarget} object (which must be either a collection, array,
	 * map or stream), by evaluating the supplied expression.
	 * <p>
	 * If a {@code Collection} or {@code Map} is used, the original instance will be
	 * modified to contain the elements for which the permission expression evaluates to
	 * {@code true}. For an array, a new array instance will be returned.
	 */
	@Override
	public Object filter(Object filterTarget, Expression filterExpression, EvaluationContext ctx) {
		MethodSecurityExpressionOperations rootObject = (MethodSecurityExpressionOperations) ctx.getRootObject()
				.getValue();
		this.logger.debug(LogMessage.format("Filtering with expression: %s", filterExpression.getExpressionString()));
		if (filterTarget instanceof Collection) {
			return filterCollection((Collection<?>) filterTarget, filterExpression, ctx, rootObject);
		}
		if (filterTarget.getClass().isArray()) {
			return filterArray((Object[]) filterTarget, filterExpression, ctx, rootObject);
		}
		if (filterTarget instanceof Map) {
			return filterMap((Map<?, ?>) filterTarget, filterExpression, ctx, rootObject);
		}
		if (filterTarget instanceof Stream) {
			return filterStream((Stream<?>) filterTarget, filterExpression, ctx, rootObject);
		}
		throw new IllegalArgumentException(
				"Filter target must be a collection, array, map or stream type, but was " + filterTarget);
	}

	private <T> Object filterCollection(Collection<T> filterTarget, Expression filterExpression, EvaluationContext ctx,
			MethodSecurityExpressionOperations rootObject) {
		this.logger.debug(LogMessage.format("Filtering collection with %s elements", filterTarget.size()));
		List<T> retain = new ArrayList<>(filterTarget.size());
		if (this.permissionCacheOptimizer != null) {
			this.permissionCacheOptimizer.cachePermissionsFor(rootObject.getAuthentication(), filterTarget);
		}
		for (T filterObject : filterTarget) {
			rootObject.setFilterObject(filterObject);
			if (ExpressionUtils.evaluateAsBoolean(filterExpression, ctx)) {
				retain.add(filterObject);
			}
		}
		this.logger.debug(LogMessage.format("Retaining elements: %s", retain));
		filterTarget.clear();
		filterTarget.addAll(retain);
		return filterTarget;
	}

	private Object filterArray(Object[] filterTarget, Expression filterExpression, EvaluationContext ctx,
			MethodSecurityExpressionOperations rootObject) {
		List<Object> retain = new ArrayList<>(filterTarget.length);
		this.logger.debug(LogMessage.format("Filtering array with %s elements", filterTarget.length));
		if (this.permissionCacheOptimizer != null) {
			this.permissionCacheOptimizer.cachePermissionsFor(rootObject.getAuthentication(),
					Arrays.asList(filterTarget));
		}
		for (Object filterObject : filterTarget) {
			rootObject.setFilterObject(filterObject);
			if (ExpressionUtils.evaluateAsBoolean(filterExpression, ctx)) {
				retain.add(filterObject);
			}
		}
		this.logger.debug(LogMessage.format("Retaining elements: %s", retain));
		Object[] filtered = (Object[]) Array.newInstance(filterTarget.getClass().getComponentType(), retain.size());
		for (int i = 0; i < retain.size(); i++) {
			filtered[i] = retain.get(i);
		}
		return filtered;
	}

	private <K, V> Object filterMap(final Map<K, V> filterTarget, Expression filterExpression, EvaluationContext ctx,
			MethodSecurityExpressionOperations rootObject) {
		Map<K, V> retain = new LinkedHashMap<>(filterTarget.size());
		this.logger.debug(LogMessage.format("Filtering map with %s elements", filterTarget.size()));
		for (Map.Entry<K, V> filterObject : filterTarget.entrySet()) {
			rootObject.setFilterObject(filterObject);
			if (ExpressionUtils.evaluateAsBoolean(filterExpression, ctx)) {
				retain.put(filterObject.getKey(), filterObject.getValue());
			}
		}
		this.logger.debug(LogMessage.format("Retaining elements: %s", retain));
		filterTarget.clear();
		filterTarget.putAll(retain);
		return filterTarget;
	}

	private Object filterStream(final Stream<?> filterTarget, Expression filterExpression, EvaluationContext ctx,
			MethodSecurityExpressionOperations rootObject) {
		return filterTarget.filter((filterObject) -> {
			rootObject.setFilterObject(filterObject);
			return ExpressionUtils.evaluateAsBoolean(filterExpression, ctx);
		}).onClose(filterTarget::close);
	}

	/**
	 * Sets the {@link AuthenticationTrustResolver} to be used. The default is
	 * {@link AuthenticationTrustResolverImpl}.
	 * @param trustResolver the {@link AuthenticationTrustResolver} to use. Cannot be
	 * null.
	 */
	public void setTrustResolver(AuthenticationTrustResolver trustResolver) {
		Assert.notNull(trustResolver, "trustResolver cannot be null");
		this.trustResolver = trustResolver;
	}

	/**
	 * @return The current {@link AuthenticationTrustResolver}
	 */
	protected AuthenticationTrustResolver getTrustResolver() {
		return this.trustResolver;
	}

	/**
	 * Sets the {@link ParameterNameDiscoverer} to use. The default is
	 * {@link DefaultSecurityParameterNameDiscoverer}.
	 * @param parameterNameDiscoverer
	 */
	public void setParameterNameDiscoverer(ParameterNameDiscoverer parameterNameDiscoverer) {
		this.parameterNameDiscoverer = parameterNameDiscoverer;
	}

	/**
	 * @return The current {@link ParameterNameDiscoverer}
	 */
	protected ParameterNameDiscoverer getParameterNameDiscoverer() {
		return this.parameterNameDiscoverer;
	}

	public void setPermissionCacheOptimizer(PermissionCacheOptimizer permissionCacheOptimizer) {
		this.permissionCacheOptimizer = permissionCacheOptimizer;
	}

	@Override
	public void setReturnObject(Object returnObject, EvaluationContext ctx) {
		((MethodSecurityExpressionOperations) ctx.getRootObject().getValue()).setReturnObject(returnObject);
	}

	/**
	 * <p>
	 * Sets the default prefix to be added to
	 * {@link org.springframework.security.access.expression.SecurityExpressionRoot#hasAnyRole(String...)}
	 * or
	 * {@link org.springframework.security.access.expression.SecurityExpressionRoot#hasRole(String)}.
	 * For example, if hasRole("ADMIN") or hasRole("ROLE_ADMIN") is passed in, then the
	 * role ROLE_ADMIN will be used when the defaultRolePrefix is "ROLE_" (default).
	 * </p>
	 *
	 * <p>
	 * If null or empty, then no default role prefix is used.
	 * </p>
	 * @param defaultRolePrefix the default prefix to add to roles. Default "ROLE_".
	 */
	public void setDefaultRolePrefix(String defaultRolePrefix) {
		this.defaultRolePrefix = defaultRolePrefix;
	}

	/**
	 * @return The default role prefix
	 */
	protected String getDefaultRolePrefix() {
		return this.defaultRolePrefix;
	}

}

相关信息

spring security 源码目录

相关文章

spring security AbstractExpressionBasedMethodConfigAttribute 源码

spring security ExpressionBasedAnnotationAttributeFactory 源码

spring security ExpressionBasedPostInvocationAdvice 源码

spring security ExpressionBasedPreInvocationAdvice 源码

spring security MethodSecurityEvaluationContext 源码

spring security MethodSecurityExpressionHandler 源码

spring security MethodSecurityExpressionOperations 源码

spring security MethodSecurityExpressionRoot 源码

spring security PostInvocationExpressionAttribute 源码

spring security PreInvocationExpressionAttribute 源码

0  赞