spring security FilterInvocation 源码

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

spring security FilterInvocation 代码

文件路径:/web/src/main/java/org/springframework/security/web/FilterInvocation.java

/*
 * Copyright 2002-2021 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.web;

import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodHandles.Lookup;
import java.lang.invoke.MethodType;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Collections;
import java.util.Enumeration;
import java.util.LinkedHashMap;
import java.util.Map;

import jakarta.servlet.FilterChain;
import jakarta.servlet.ServletContext;
import jakarta.servlet.ServletRequest;
import jakarta.servlet.ServletResponse;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletRequestWrapper;
import jakarta.servlet.http.HttpServletResponse;

import org.springframework.http.HttpHeaders;
import org.springframework.security.web.util.UrlUtils;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;

/**
 * Holds objects associated with a HTTP filter.
 * <P>
 * Guarantees the request and response are instances of <code>HttpServletRequest</code>
 * and <code>HttpServletResponse</code>, and that there are no <code>null</code> objects.
 * <p>
 * Required so that security system classes can obtain access to the filter environment,
 * as well as the request and response.
 *
 * @author Ben Alex
 * @author colin sampaleanu
 * @author Luke Taylor
 * @author Rob Winch
 */
public class FilterInvocation {

	static final FilterChain DUMMY_CHAIN = (req, res) -> {
		throw new UnsupportedOperationException("Dummy filter chain");
	};

	private FilterChain chain;

	private HttpServletRequest request;

	private HttpServletResponse response;

	public FilterInvocation(ServletRequest request, ServletResponse response, FilterChain chain) {
		Assert.isTrue(request != null && response != null && chain != null, "Cannot pass null values to constructor");
		this.request = (HttpServletRequest) request;
		this.response = (HttpServletResponse) response;
		this.chain = chain;
	}

	public FilterInvocation(String servletPath, String method) {
		this(null, servletPath, method);
	}

	public FilterInvocation(String contextPath, String servletPath, String method) {
		this(contextPath, servletPath, method, null);
	}

	public FilterInvocation(String contextPath, String servletPath, String method, ServletContext servletContext) {
		this(contextPath, servletPath, null, null, method, servletContext);
	}

	public FilterInvocation(String contextPath, String servletPath, String pathInfo, String query, String method) {
		this(contextPath, servletPath, pathInfo, query, method, null);
	}

	public FilterInvocation(String contextPath, String servletPath, String pathInfo, String query, String method,
			ServletContext servletContext) {
		DummyRequest request = new DummyRequest();
		contextPath = (contextPath != null) ? contextPath : "/cp";
		request.setContextPath(contextPath);
		request.setServletPath(servletPath);
		request.setRequestURI(contextPath + servletPath + ((pathInfo != null) ? pathInfo : ""));
		request.setPathInfo(pathInfo);
		request.setQueryString(query);
		request.setMethod(method);
		request.setServletContext(servletContext);
		this.request = request;
	}

	public FilterChain getChain() {
		return this.chain;
	}

	/**
	 * Indicates the URL that the user agent used for this request.
	 * <p>
	 * The returned URL does <b>not</b> reflect the port number determined from a
	 * {@link org.springframework.security.web.PortResolver}.
	 * @return the full URL of this request
	 */
	public String getFullRequestUrl() {
		return UrlUtils.buildFullRequestUrl(this.request);
	}

	public HttpServletRequest getHttpRequest() {
		return this.request;
	}

	public HttpServletResponse getHttpResponse() {
		return this.response;
	}

	/**
	 * Obtains the web application-specific fragment of the URL.
	 * @return the URL, excluding any server name, context path or servlet path
	 */
	public String getRequestUrl() {
		return UrlUtils.buildRequestUrl(this.request);
	}

	public HttpServletRequest getRequest() {
		return getHttpRequest();
	}

	public HttpServletResponse getResponse() {
		return getHttpResponse();
	}

	@Override
	public String toString() {
		if (StringUtils.isEmpty(this.request.getMethod())) {
			return "filter invocation [" + getRequestUrl() + "]";
		}
		else {
			return "filter invocation [" + this.request.getMethod() + " " + getRequestUrl() + "]";
		}
	}

	static class DummyRequest extends HttpServletRequestWrapper {

		private static final HttpServletRequest UNSUPPORTED_REQUEST = (HttpServletRequest) Proxy.newProxyInstance(
				DummyRequest.class.getClassLoader(), new Class[] { HttpServletRequest.class },
				new UnsupportedOperationExceptionInvocationHandler());

		private String requestURI;

		private String contextPath = "";

		private String servletPath;

		private String pathInfo;

		private String queryString;

		private String method;

		private ServletContext servletContext;

		private final HttpHeaders headers = new HttpHeaders();

		private final Map<String, String[]> parameters = new LinkedHashMap<>();

		DummyRequest() {
			super(UNSUPPORTED_REQUEST);
		}

		@Override
		public String getCharacterEncoding() {
			return "UTF-8";
		}

		@Override
		public Object getAttribute(String attributeName) {
			return null;
		}

		void setRequestURI(String requestURI) {
			this.requestURI = requestURI;
		}

		void setPathInfo(String pathInfo) {
			this.pathInfo = pathInfo;
		}

		@Override
		public String getRequestURI() {
			return this.requestURI;
		}

		void setContextPath(String contextPath) {
			this.contextPath = contextPath;
		}

		@Override
		public String getContextPath() {
			return this.contextPath;
		}

		void setServletPath(String servletPath) {
			this.servletPath = servletPath;
		}

		@Override
		public String getServletPath() {
			return this.servletPath;
		}

		void setMethod(String method) {
			this.method = method;
		}

		@Override
		public String getMethod() {
			return this.method;
		}

		@Override
		public String getPathInfo() {
			return this.pathInfo;
		}

		@Override
		public String getQueryString() {
			return this.queryString;
		}

		void setQueryString(String queryString) {
			this.queryString = queryString;
		}

		@Override
		public String getServerName() {
			return null;
		}

		@Override
		public String getHeader(String name) {
			return this.headers.getFirst(name);
		}

		@Override
		public Enumeration<String> getHeaders(String name) {
			return Collections.enumeration(this.headers.get(name));
		}

		@Override
		public Enumeration<String> getHeaderNames() {
			return Collections.enumeration(this.headers.keySet());
		}

		@Override
		public int getIntHeader(String name) {
			String value = this.headers.getFirst(name);
			if (value == null) {
				return -1;
			}
			return Integer.parseInt(value);
		}

		void addHeader(String name, String value) {
			this.headers.add(name, value);
		}

		@Override
		public String getParameter(String name) {
			String[] array = this.parameters.get(name);
			return (array != null && array.length > 0) ? array[0] : null;
		}

		@Override
		public Map<String, String[]> getParameterMap() {
			return Collections.unmodifiableMap(this.parameters);
		}

		@Override
		public Enumeration<String> getParameterNames() {
			return Collections.enumeration(this.parameters.keySet());
		}

		@Override
		public String[] getParameterValues(String name) {
			return this.parameters.get(name);
		}

		void setParameter(String name, String... values) {
			this.parameters.put(name, values);
		}

		@Override
		public ServletContext getServletContext() {
			return this.servletContext;
		}

		void setServletContext(ServletContext servletContext) {
			this.servletContext = servletContext;
		}

	}

	static final class UnsupportedOperationExceptionInvocationHandler implements InvocationHandler {

		private static final float JAVA_VERSION = Float.parseFloat(System.getProperty("java.class.version", "52"));

		@Override
		public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
			if (method.isDefault()) {
				return invokeDefaultMethod(proxy, method, args);
			}
			throw new UnsupportedOperationException(method + " is not supported");
		}

		private Object invokeDefaultMethod(Object proxy, Method method, Object[] args) throws Throwable {
			if (isJdk8OrEarlier()) {
				return invokeDefaultMethodForJdk8(proxy, method, args);
			}
			return MethodHandles.lookup()
					.findSpecial(method.getDeclaringClass(), method.getName(),
							MethodType.methodType(method.getReturnType(), new Class[0]), method.getDeclaringClass())
					.bindTo(proxy).invokeWithArguments(args);
		}

		private Object invokeDefaultMethodForJdk8(Object proxy, Method method, Object[] args) throws Throwable {
			Constructor<Lookup> constructor = Lookup.class.getDeclaredConstructor(Class.class);
			constructor.setAccessible(true);
			Class<?> clazz = method.getDeclaringClass();
			return constructor.newInstance(clazz).in(clazz).unreflectSpecial(method, clazz).bindTo(proxy)
					.invokeWithArguments(args);
		}

		private boolean isJdk8OrEarlier() {
			return JAVA_VERSION <= 52;
		}

	}

}

相关信息

spring security 源码目录

相关文章

spring security AuthenticationEntryPoint 源码

spring security DefaultRedirectStrategy 源码

spring security DefaultSecurityFilterChain 源码

spring security FilterChainProxy 源码

spring security PortMapper 源码

spring security PortMapperImpl 源码

spring security PortResolver 源码

spring security PortResolverImpl 源码

spring security RedirectStrategy 源码

spring security RequestMatcherRedirectFilter 源码

0  赞