SpringSecurity过滤器之SecurityContextHolderAwareRequestFilter,RequestCacheAwareFilter

shigongp / 2023-05-03 / 原文

SecurityContextHolderAwareRequestFilter

SecurityContextHolderAwareRequestFilter对Servelet3.0的api做了封装。

public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
		throws IOException, ServletException {
	chain.doFilter(this.requestFactory.create((HttpServletRequest) req, (HttpServletResponse) res), res);
}

requestFactory是HttpServlet3RequestFactory。

HttpServlet3RequestFactory#create

public HttpServletRequest create(HttpServletRequest request, HttpServletResponse response) {
	return new Servlet3SecurityContextHolderAwareRequestWrapper(request, this.rolePrefix, response);
}

rolePrefix是ROLE_。用于添加角色前缀。

private class Servlet3SecurityContextHolderAwareRequestWrapper extends SecurityContextHolderAwareRequestWrapper {

	private final HttpServletResponse response;

	Servlet3SecurityContextHolderAwareRequestWrapper(HttpServletRequest request, String rolePrefix,
			HttpServletResponse response) {
		super(request, HttpServlet3RequestFactory.this.trustResolver, rolePrefix);
		this.response = response;
	}

	@Override
	public AsyncContext getAsyncContext() {
		AsyncContext asyncContext = super.getAsyncContext();
		if (asyncContext == null) {
			return null;
		}
		return new SecurityContextAsyncContext(asyncContext);
	}

	@Override
	public AsyncContext startAsync() {
		AsyncContext startAsync = super.startAsync();
		return new SecurityContextAsyncContext(startAsync);
	}

	@Override
	public AsyncContext startAsync(ServletRequest servletRequest, ServletResponse servletResponse)
			throws IllegalStateException {
		AsyncContext startAsync = super.startAsync(servletRequest, servletResponse);
		return new SecurityContextAsyncContext(startAsync);
	}

	@Override
	public boolean authenticate(HttpServletResponse response) throws IOException, ServletException {
		AuthenticationEntryPoint entryPoint = HttpServlet3RequestFactory.this.authenticationEntryPoint;
		if (entryPoint == null) {
			HttpServlet3RequestFactory.this.logger.debug(
					"authenticationEntryPoint is null, so allowing original HttpServletRequest to handle authenticate");
			return super.authenticate(response);
		}
		if (isAuthenticated()) {
			return true;
		}
		entryPoint.commence(this, response,
				new AuthenticationCredentialsNotFoundException("User is not Authenticated"));
		return false;
	}

	@Override
	public void login(String username, String password) throws ServletException {
		if (isAuthenticated()) {
			throw new ServletException("Cannot perform login for '" + username + "' already authenticated as '"
					+ getRemoteUser() + "'");
		}
		AuthenticationManager authManager = HttpServlet3RequestFactory.this.authenticationManager;
		if (authManager == null) {
			HttpServlet3RequestFactory.this.logger.debug(
					"authenticationManager is null, so allowing original HttpServletRequest to handle login");
			super.login(username, password);
			return;
		}
		Authentication authentication = getAuthentication(authManager, username, password);
		SecurityContext context = SecurityContextHolder.createEmptyContext();
		context.setAuthentication(authentication);
		SecurityContextHolder.setContext(context);
	}

	private Authentication getAuthentication(AuthenticationManager authManager, String username, String password)
			throws ServletException {
		try {
			UsernamePasswordAuthenticationToken authentication = UsernamePasswordAuthenticationToken
					.unauthenticated(username, password);
			Object details = HttpServlet3RequestFactory.this.authenticationDetailsSource.buildDetails(this);
			authentication.setDetails(details);
			return authManager.authenticate(authentication);
		}
		catch (AuthenticationException ex) {
			SecurityContextHolder.clearContext();
			throw new ServletException(ex.getMessage(), ex);
		}
	}

	@Override
	public void logout() throws ServletException {
		List<LogoutHandler> handlers = HttpServlet3RequestFactory.this.logoutHandlers;
		if (CollectionUtils.isEmpty(handlers)) {
			HttpServlet3RequestFactory.this.logger
					.debug("logoutHandlers is null, so allowing original HttpServletRequest to handle logout");
			super.logout();
			return;
		}
		Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
		for (LogoutHandler handler : handlers) {
			handler.logout(this, this.response, authentication);
		}
	}

	private boolean isAuthenticated() {
		return getUserPrincipal() != null;
	}

}

Servlet3SecurityContextHolderAwareRequestWrapper对Servlet3.0的方法做了封装。方法中有AsyncContext的是与异步web相关。对Servlet3.0的登录,登出,认证方法都做了封装。父类SecurityContextHolderAwareRequestWrapper重写了HttpServletRequestWrapper的getUserPrincipal(),isUserInRole(String),getRemoteUser()。

RequestCacheAwareFilter

public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
		throws IOException, ServletException {
	HttpServletRequest wrappedSavedRequest = this.requestCache.getMatchingRequest((HttpServletRequest) request,
			(HttpServletResponse) response);
	chain.doFilter((wrappedSavedRequest != null) ? wrappedSavedRequest : request, response);
}

如果在requestCache有保存的请求直接用否则用ServletRequest。默认是HttpSessionRequestCache。将SavedRequest保存到Session中。