Ser competente en spring-security1 desde el código fuente

Consulte el maestro superior de la estación b: Portal

Frontier: este capítulo: miembros importantes de spring-security WebSecurity, HttpSecurity, SecurityBuilder, SecurityFilterChain, FilterChainProxy

Puntos clave : WebSecurity, HttpSecurity, todos implementan la interfaz SecurityBuilder para construir objetos

El papel de WebSecurity:

WebSecurity es, en última instancia, para construir Filter

Primer vistazo a su estructura:

public final class WebSecurity extends
		AbstractConfiguredSecurityBuilder<Filter, WebSecurity> implements
		SecurityBuilder<Filter>, ApplicationContextAware{
    
    
  
}

Interludio : De hecho, el AbstractConfiguredSecurityBuilder heredado por WebSecurity ya ha implementado SecurityBuilder , lo que significa que WebSecurity hereda AbstractConfiguredSecurityBuilder y ya puede completar el trabajo. ¿Qué significa implementar SecurityBuilder nuevamente ? Entendimiento: Desde la perspectiva de las personas que miran el código, es más claro que WebSecurity implementa SecurityBuilder , que es nuestra interfaz más importante, y el Filtro genérico ya sabe que el objeto a construir es Filter .

En resumen : podemos ver aquí de inmediato cuál es el objeto Object que WebSecurity finalmente construye. es Filtro.

Escribir o no implementar SecurityBuilder puede hacer el trabajo

El papel de HttpSecurity

Utilice el método de WebSecurity ahora mismo para comprender

public final class HttpSecurity extends
		AbstractConfiguredSecurityBuilder<DefaultSecurityFilterChain, HttpSecurity>
		implements SecurityBuilder<DefaultSecurityFilterChain>,
		HttpSecurityBuilder<HttpSecurity> {
    
    
      
    }

HttpSecurity es construir el objeto DefaultSecurityFilterChain . Es la clase de implementación predeterminada de SecurityFilterChain

SecurityFilterChain

SecurityFilterChain : es una interfaz, la implementación predeterminada es DefaultSecurityFilterChain

/**
Defines a filter chain which is capable of being matched against an HttpServletRequest. in order to decide whether it applies to that request.
定义这样的一个过滤器链去匹配一个特定的request,然后决定这个request能不能应用这个List<Filter>
*/
public interface SecurityFilterChain {
    
    

	boolean matches(HttpServletRequest request);

	List<Filter> getFilters();
}

SecurityFilterChain también es un miembro importante de spring-security. Dos métodos:

1. Si las coincidencias pueden coincidir con la solicitud

2. Si la coincidencia es exitosa, todos los filtros en el método getFilters() se aplican una vez.

Implementación predeterminada de SecurityFilterChain

DefaultSecurityFilterChain

public final class DefaultSecurityFilterChain implements SecurityFilterChain {
    
    
  // 在matches中判断能不能匹配request
  private final RequestMatcher requestMatcher;
	private final List<Filter> filters;
  public DefaultSecurityFilterChain(RequestMatcher requestMatcher, Filter... filters) {
    
    
		this(requestMatcher, Arrays.asList(filters));
	}

	public DefaultSecurityFilterChain(RequestMatcher requestMatcher, List<Filter> filters) {
    
    
		logger.info("Creating filter chain: " + requestMatcher + ", " + filters);
		this.requestMatcher = requestMatcher;
		this.filters = new ArrayList<>(filters);
	}

	public RequestMatcher getRequestMatcher() {
    
    
		return requestMatcher;
	}
	// 匹配成功就把Filter应用一遍
	public List<Filter> getFilters() {
    
    
		return filters;
	}
  // 在matches中判断能不能匹配request
  public boolean matches(HttpServletRequest request) {
    
    
		return requestMatcher.matches(request);
	}
}

¿Qué tipo de filtro construye WebSecurity?

public interface SecurityBuilder<O> {
    
    

   /**
    * Builds the object and returns it or null.
    *
    * @return the Object to be built or null if the implementation allows it.
    * @throws Exception if an error occurred when building the Object
    */
   O build() throws Exception;
}

Mire su implementación a través del método de compilación: AbstractSecurityBuilder implementa el método de compilación en la interfaz de SecurityBuilder

El trabajo de construcción del método doBuild en la clase abstracta AbstractSecurityBuilder se delega a la subclase para su implementación.

public abstract class AbstractSecurityBuilder<O> implements SecurityBuilder<O>{
    
    
  
  private AtomicBoolean building = new AtomicBoolean();

	private O object;
  //AbstractSecurityBuilder实现了SecurityBuilder接口中的build方法
  public final O build() throws Exception {
    
    
		if (this.building.compareAndSet(false, true)) {
    
    
			this.object = doBuild();
			return this.object;
		}
    // 解决了重复构建问题 如果再构建一次就抛出异常了
		throw new AlreadyBuiltException("This object has already been built");
	}
  // 构建工作 doBuild 方法
  protected abstract O doBuild() throws Exception;
}

sigue bajando

AbstractConfiguredSecurityBuilder también es una clase abstracta. Implementa el método doBuild de la clase padre

public abstract class AbstractConfiguredSecurityBuilder<O, B extends SecurityBuilder<O>>
		extends AbstractSecurityBuilder<O> {
    
    
  
  
     @Override
      protected final O doBuild() throws Exception {
    
    
        // 加锁 此阶段只能一个线程执行
        synchronized (configurers) {
    
    
          buildState = BuildState.INITIALIZING;
					// 留给子类实现的模版方法  不强制子类实现 即不重要的方法
          beforeInit();
          init();

          buildState = BuildState.CONFIGURING;
					// 留给子类实现的模版方法 不强制子类实现 即不重要的方法
          beforeConfigure();
          configure();

          buildState = BuildState.BUILDING;
					// 重要方法  有三个类实现它 AuthenticationManagerBuilder HttpSecurity WebSecurity
          O result = performBuild();

          buildState = BuildState.BUILT;

          return result;
        }
      } 
  //不强制子类实现
  protected void beforeInit() throws Exception {
    
    
	}
  //不强制子类实现
  protected void beforeConfigure() throws Exception {
    
    
	}
  
  // 重要方法
  protected abstract O performBuild() throws Exception;
  
}

Aquí usamos el método performBuild(); para construir el Objeto que finalmente necesitamos, y la lógica central está en el método performBuild.

Hay tres clases que lo implementan AuthenticationManagerBuilder, HttpSecurity, WebSecurity

Método performBuild de HttpSecurity

@Override
	protected DefaultSecurityFilterChain performBuild() {
    
    
		filters.sort(comparator);
		return new DefaultSecurityFilterChain(requestMatcher, filters);
	}

Lo que finalmente se devuelve es DefaultSecurityFilterChain. Como se mencionó anteriormente, lo que HttpSecurity necesita construir es DefaultSecurityFilterChain. Luego, el trabajo de HttpSecurity se completa.

Método performBuild de WebSecurity

El papel de WebSecurity: construir un filtro Obviamente, construir el trabajo aquí

	@Override
	protected Filter performBuild() throws Exception {
    
    
		Assert.state(
				!securityFilterChainBuilders.isEmpty(),
				() -> "At least one SecurityBuilder<? extends SecurityFilterChain> needs to be specified. "
						+ "Typically this done by adding a @Configuration that extends WebSecurityConfigurerAdapter. "
						+ "More advanced users can invoke "
						+ WebSecurity.class.getSimpleName()
						+ ".addSecurityFilterChainBuilder directly");
		int chainSize = ignoredRequests.size() + securityFilterChainBuilders.size();
		List<SecurityFilterChain> securityFilterChains = new ArrayList<>(
				chainSize);
		for (RequestMatcher ignoredRequest : ignoredRequests) {
    
    
			securityFilterChains.add(new DefaultSecurityFilterChain(ignoredRequest));
		}
		for (SecurityBuilder<? extends SecurityFilterChain> securityFilterChainBuilder : securityFilterChainBuilders) {
    
    
			securityFilterChains.add(securityFilterChainBuilder.build());
		}
    // FilterChainProxy 就是Filter的一个变种 最终还是一个Filter
		FilterChainProxy filterChainProxy = new FilterChainProxy(securityFilterChains);
		if (httpFirewall != null) {
    
    
			filterChainProxy.setFirewall(httpFirewall);
		}
		filterChainProxy.afterPropertiesSet();

		Filter result = filterChainProxy;
    //debugEnabled:这个是通过 @EnableWebSecurity(dubug=true)开启的
		if (debugEnabled) {
    
    
			logger.warn("\n\n"
					+ "********************************************************************\n"
					+ "**********        Security debugging is enabled.       *************\n"
					+ "**********    This may include sensitive information.  *************\n"
					+ "**********      Do not use in a production system!     *************\n"
					+ "********************************************************************\n\n");
			result = new DebugFilter(filterChainProxy);
		}
		postBuildAction.run();
		return result;
	}

FilterChainProxy

Conocimiento previo:

SecurityFilterChain : es una cadena de filtro. Como se mencionó anteriormente, si la cadena de filtro se puede aplicar depende de si la solicitud puede coincidir.

public class FilterChainProxy extends GenericFilterBean {
    
    
  
  //传了一堆 SecurityFilterChain
  public FilterChainProxy(List<SecurityFilterChain> filterChains) {
    
    
		this.filterChains = filterChains;
	}
  
  //  是Filter的一个主要方法  doFilter做过滤的 控制过滤器只能执行一次
  @Override
	public void doFilter(ServletRequest request, ServletResponse response,
			FilterChain chain) throws IOException, ServletException {
    
    
		boolean clearContext = request.getAttribute(FILTER_APPLIED) == null;
		if (clearContext) {
    
    
			try {
    
    
				request.setAttribute(FILTER_APPLIED, Boolean.TRUE);
        //核心方法 
				doFilterInternal(request, response, chain);
			}
			finally {
    
    
				SecurityContextHolder.clearContext();
				request.removeAttribute(FILTER_APPLIED);
			}
		}
		else {
    
    
			doFilterInternal(request, response, chain);
		}
	}
  	
  	//FilterChain tomcat下的一个接口 他的最主要实现是 ApplicationFilterChain
  	private void doFilterInternal(ServletRequest request, ServletResponse response,
			FilterChain chain) throws IOException, ServletException {
    
    

		FirewalledRequest fwRequest = firewall
				.getFirewalledRequest((HttpServletRequest) request);
		HttpServletResponse fwResponse = firewall
				.getFirewalledResponse((HttpServletResponse) response);
		// 拿到一堆Filters  这里是重点
		List<Filter> filters = getFilters(fwRequest);

		if (filters == null || filters.size() == 0) {
    
    
			if (logger.isDebugEnabled()) {
    
    
				logger.debug(UrlUtils.buildRequestUrl(fwRequest)
						+ (filters == null ? " has no matching filters"
								: " has an empty filter list"));
			}

			fwRequest.reset();

			chain.doFilter(fwRequest, fwResponse);

			return;
		}
		// VirtualFilterChain 虚拟的过滤器链  chain 最顶层的过滤器链
    // VirtualFilterChain最终就是 把 这个参数中的 filters 挨个应用一遍
		VirtualFilterChain vfc = new VirtualFilterChain(fwRequest, chain, filters);
    // 虚拟的过滤器链 调用了他的 doFilter方法
		vfc.doFilter(fwRequest, fwResponse);
	}
  
  // 如果应用中定义了多个SecurityFilterChain 如果想要第一个匹配的去执行 此时需要控制一下顺序 实现Order接口 或者Order注解控制?
  private List<Filter> getFilters(HttpServletRequest request) {
    
    
		for (SecurityFilterChain chain : filterChains) {
    
    
      // 匹配到第一个即成功
			if (chain.matches(request)) {
    
    
				return chain.getFilters();
			}
		}

		return null;
	}
  
  		@Override
		public void doFilter(ServletRequest request, ServletResponse response)
				throws IOException, ServletException {
    
    
			if (currentPosition == size) {
    
    
				if (logger.isDebugEnabled()) {
    
    
					logger.debug(UrlUtils.buildRequestUrl(firewalledRequest)
							+ " reached end of additional filter chain; proceeding with original chain");
				}

				// Deactivate path stripping as we exit the security filter chain
				this.firewalledRequest.reset();

				originalChain.doFilter(request, response);
			}
			else {
    
    
				currentPosition++;

				Filter nextFilter = additionalFilters.get(currentPosition - 1);

				if (logger.isDebugEnabled()) {
    
    
					logger.debug(UrlUtils.buildRequestUrl(firewalledRequest)
							+ " at position " + currentPosition + " of " + size
							+ " in additional filter chain; firing Filter: '"
							+ nextFilter.getClass().getSimpleName() + "'");
				}

				nextFilter.doFilter(request, response, this);
			}
		}
	}
}

por fin

Hasta ahora, se ha analizado el proceso de seguridad de primavera y su capa superior es un filtro.Este filtro es FilterChainProxy.

Hay un montón de SecurityFilterChains en FilterChainProxy private List<SecurityFilterChain> filterChains;(este es un atributo en la clase FilterChainProxy), y estos SecurityFilterChains tienen un comparador llamado RequestMatcher, que es un atributo en DefaultSecurityFilterChain, la clase de implementación predeterminada de SecurityFilterChain.

RequestMatcher es una interfaz con varias implementaciones que se utilizan para hacer coincidir las solicitudes.

Resumen del proceso:

El FilterChainProxy entra llamando al método doFilter, luego llama al método doFilterInternal, a través de getFilters de acuerdo con el objeto HttpServletRequest para hacer coincidir el primer SecurityFilterChain coincidente y eliminar los filtros.

Se crea un objeto VirtualFilterChain para llamar a su doFilter uno por uno.

Supongo que te gusta

Origin blog.csdn.net/qq_43566782/article/details/129353030
Recomendado
Clasificación