Spring Security 之默认过滤器链的SecurityContextPersistenceFilter(七)

1.SecurityContextPersistenceFilter 是干啥的

SecurityContextPersistenceFilter 是用来在认证之前从SecurityContextRepository获取SecurityContext,然后放入SecurityContextHolder中。

然后在其他filter执行完毕之后,再将SecurityContext 通过SecurityContextRepository存储到想要存储的地方,然后清理掉SecurityContextHolder中的SecurityContext




2.doFilter源码解读

public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
			throws IOException, ServletException {
		HttpServletRequest request = (HttpServletRequest) req;
		HttpServletResponse response = (HttpServletResponse) res;

		if (request.getAttribute(FILTER_APPLIED) != null) {
			// ensure that filter is only applied once per request
			// 这个就是确保一个request只会走一次SecurityContextPersistenceFilter 
			chain.doFilter(request, response);
			return;
		}

		final boolean debug = logger.isDebugEnabled();
		// 给request打标记,说明这个Filter已经执行过一次了。
		request.setAttribute(FILTER_APPLIED, Boolean.TRUE);

		if (forceEagerSessionCreation) {
			// 要不要先创建session
			HttpSession session = request.getSession();

			if (debug && session.isNew()) {
				logger.debug("Eagerly created session: " + session.getId());
			}
		}
	
		HttpRequestResponseHolder holder = new HttpRequestResponseHolder(request,
				response);
		// 通过SecurityContextRepository加载SecurityContext
		// 默认使用的是HttpSessionSecurityContxtReposity
		// 这个就是说,默认是从session中获取。如果session里面获取不到就创建一个新的SecurityContext
		SecurityContext contextBeforeChainExecution = repo.loadContext(holder);

		try {
			// 将 SecurityContext 丢入 SecurityContextHolder
			SecurityContextHolder.setContext(contextBeforeChainExecution);
			// 执行其他拦截器
			chain.doFilter(holder.getRequest(), holder.getResponse());

		}
		finally {
			// 在其他拦截器执行完后,再将SecurityContext 从 SecurityContextHolder中移除
			SecurityContext contextAfterChainExecution = SecurityContextHolder
					.getContext();
			// Crucial removal of SecurityContextHolder contents - do this before anything
			// else.
			SecurityContextHolder.clearContext();
			// 保存经过其他拦截器操作过后的SecurityContext到指定地方
			//repo的默认值是HttpSessionSecurityContxtReposity
			// 也就是保存到session中去
			repo.saveContext(contextAfterChainExecution, holder.getRequest(),
					holder.getResponse());
			// ok,这个filter执行完毕,移除重复标记
			request.removeAttribute(FILTER_APPLIED);

			if (debug) {
				logger.debug("SecurityContextHolder now cleared, as request processing completed");
			}
		}
	}

简述流程:

1.从SecurityContextRepository中获取SecurityContext

2.将SecurityContext存入SecurityContextHolder

3.执行其他过滤器,对SecurityContext进行处理

4.在其他的执行完后,将SecurityContextSecurityContextHolder中清除,并通过SecurityContextRepository进行回写。



3.题外话之默认的HttpSessionSecurityContextRepository

这是默认的SecurityContext的存储器。其实就是将SecurityContext存储在session中。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-3LQteQhm-1625724984029)(https://s3-us-west-2.amazonaws.com/secure.notion-static.com/781f14f0-9f3e-4f30-b672-5bf83fcd62f4/Untitled.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AUXkbMez-1625724984031)(https://s3-us-west-2.amazonaws.com/secure.notion-static.com/4f7b4f86-df86-4c83-bd59-84b476328d6e/Untitled.png)]
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qhqvLLXt-1625724984033)(https://s3-us-west-2.amazonaws.com/secure.notion-static.com/e74cf8de-bc6b-4e08-ba45-e00c352cf8fd/Untitled.png)]

从上面我们可以看到,从session中拿SecurityContext和存SecurityContext的过程。

同时我们也可以仿造HttpSessionSecurityContextRepository去实现我们自己的SecurityContextRepository。完成对SecurityContext的储存。




4.小结

在这个类中,我们可以看到如何保证filter只执行一次。如何对SecurityContext的生命周期的把控。以及最关键的SecurityContext的存储机制和时机。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

欢谷悠扬

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值