Servlet filter 定义SecurityContext的消失

前言

今天在测试Spring security一些过滤器的功能,突然想到我们在security的过滤链中自定义认证过滤器,存放SecurityContext认证对象Authentication,以至于后续授权会根据我们自己的Authentication去实现.如果我们在Springboot里创建一个单纯的Filter,把SecurityContext设置认证对象Authentication,是否会在spring security中同样生效呢? 经过验证,不可以.
验证之后有点想不通,SecurityContext底层TreadLocal存储的,同一个访问应该都能拿到Authentication为什么不可以使用呢.

SecurityContextPersistentFilter

对于spring security有了解的朋友可能知道这个过滤器,他是管理SecurityContext生命周期的一个过滤器,也是在进入Spring security过滤链中比较靠前执行的过滤器.我们来观察这一段代码:

private void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain chain)
			throws IOException, ServletException {
		// ensure that filter is only applied once per request
		if (request.getAttribute(FILTER_APPLIED) != null) {
			chain.doFilter(request, response);
			return;
		}
		request.setAttribute(FILTER_APPLIED, Boolean.TRUE);
		if (this.forceEagerSessionCreation) {
			HttpSession session = request.getSession();
			if (this.logger.isDebugEnabled() && session.isNew()) {
				this.logger.debug(LogMessage.format("Created session %s eagerly", session.getId()));
			}
		}
		HttpRequestResponseHolder holder = new HttpRequestResponseHolder(request, response);
		SecurityContext contextBeforeChainExecution = this.repo.loadContext(holder);
		try {
			SecurityContextHolder.setContext(contextBeforeChainExecution);
			if (contextBeforeChainExecution.getAuthentication() == null) {
				logger.debug("Set SecurityContextHolder to empty SecurityContext");
			}
			else {
				if (this.logger.isDebugEnabled()) {
					this.logger
							.debug(LogMessage.format("Set SecurityContextHolder to %s", contextBeforeChainExecution));
				}
			}
			chain.doFilter(holder.getRequest(), holder.getResponse());
		}
		finally {
			SecurityContext contextAfterChainExecution = SecurityContextHolder.getContext();
			// Crucial removal of SecurityContextHolder contents before anything else.
			SecurityContextHolder.clearContext();
			this.repo.saveContext(contextAfterChainExecution, holder.getRequest(), holder.getResponse());
			request.removeAttribute(FILTER_APPLIED);
			this.logger.debug("Cleared SecurityContextHolder to complete request");
		}
	}
其中有一行代码
SecurityContext contextBeforeChainExecution = this.repo.loadContext(holder);

这段代码的意思就是,无论我们前面servlet filter 是否在SecurityContext中存放了认证信息,在SpringSecurity过滤器链开始之前,都要从这个repo(HttpSessionSecurityContextRepository是默认实现)获取一个context对象,重新放到SecurityContext,这样做就是把你的ServletFilter里的context清空了,然后才继续进入security其他过滤器中.
最后finally又有代码

	finally {
		SecurityContext contextAfterChainExecution = SecurityContextHolder.getContext();
		// Crucial removal of SecurityContextHolder contents before anything else.
		SecurityContextHolder.clearContext();
		this.repo.saveContext(contextAfterChainExecution, holder.getRequest(), holder.getResponse());
		request.removeAttribute(FILTER_APPLIED);
		this.logger.debug("Cleared SecurityContextHolder to complete request");
	}

这段代码又表示,当security的所有过滤器执行结束之后,清空SecurityContext上下文信息,同时,如果上下文有认证信息,存储到repo里,供后续使用,所以如果是session存储,只要会话存在,下一次访问不需要走认证流程依然可以保持认证状态.
这两段代码是关键.

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值