SecurityContextPersistenceFilter 在过滤器链完成后清除 SecurityContextHolder
SecurityContextPersistenceFilter clears SecurityContextHolder after filter chain is finished
我目前正在学习 Spring 安全基础知识。我正在阅读文档和源代码,因为我希望获得尽可能多的关于引擎盖下发生的事情的详细信息。除了一件事,一切都有些可以理解:
SecurityContextPersistenceFilter
过滤器 class 是 Spring 安全性的第一个过滤器,根据 this page class 的 doFilter()
方法的实现看起来像这样:
private void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
if (request.getAttribute("__spring_security_scpf_applied") != null) {
chain.doFilter(request, response);
} else {
request.setAttribute("__spring_security_scpf_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);
boolean var10 = false;
try {
var10 = true;
SecurityContextHolder.setContext(contextBeforeChainExecution);
if (contextBeforeChainExecution.getAuthentication() == null) {
this.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());
var10 = false;
} finally {
if (var10) {
SecurityContext contextAfterChainExecution = SecurityContextHolder.getContext();
SecurityContextHolder.clearContext();
this.repo.saveContext(contextAfterChainExecution, holder.getRequest(), holder.getResponse());
request.removeAttribute("__spring_security_scpf_applied");
this.logger.debug("Cleared SecurityContextHolder to complete request");
}
}
SecurityContext contextAfterChainExecution = SecurityContextHolder.getContext();
SecurityContextHolder.clearContext();
this.repo.saveContext(contextAfterChainExecution, holder.getRequest(), holder.getResponse());
request.removeAttribute("__spring_security_scpf_applied");
this.logger.debug("Cleared SecurityContextHolder to complete request");
}
}
我的问题是:显然,在过滤器链完成其工作后,SecurityContextHolder.clearContext()
方法要么在 finally 块中调用,要么在方法结束时调用。但是我知道,我仍然可以在我的控制器和服务层中使用 SecurityContextHolder.getContext()
访问 SecurityContext 对象。如果上面的代码清除了 SecurityContextHolder,那怎么可能呢?我错过了什么吗?
首先,您所指的文档是 spring security 的 4.1.2 版,该版本于 2016 年 12 月 21 日发布。Spring security 当前为 5.6.1,the filter list looks a lot different in the current documentation.
那么上面代码中你的问题的答案是,因为这一行
this.repo.saveContext(contextAfterChainExecution, holder.getRequest(), holder.getResponse());
SecurityContextHolder
是一个单例,所以 SecurityContext
被获取(这将创建一个副本)然后在 singleton
中被清除,最后 this.repo.save
保存下一次的上下文。
这是如何保存的,是不同的,默认情况下相信它使用 HttpSession(这意味着你将获得一个会话 cookie),它在 HttpSessionSecurityContextRepository 中的 Spring 中实现,但你可以设置一个单独的数据库,如果您愿意,可以永久保存它,这样它在重新启动等后仍然存在。
我目前正在学习 Spring 安全基础知识。我正在阅读文档和源代码,因为我希望获得尽可能多的关于引擎盖下发生的事情的详细信息。除了一件事,一切都有些可以理解:
SecurityContextPersistenceFilter
过滤器 class 是 Spring 安全性的第一个过滤器,根据 this page class 的 doFilter()
方法的实现看起来像这样:
private void doFilter(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
if (request.getAttribute("__spring_security_scpf_applied") != null) {
chain.doFilter(request, response);
} else {
request.setAttribute("__spring_security_scpf_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);
boolean var10 = false;
try {
var10 = true;
SecurityContextHolder.setContext(contextBeforeChainExecution);
if (contextBeforeChainExecution.getAuthentication() == null) {
this.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());
var10 = false;
} finally {
if (var10) {
SecurityContext contextAfterChainExecution = SecurityContextHolder.getContext();
SecurityContextHolder.clearContext();
this.repo.saveContext(contextAfterChainExecution, holder.getRequest(), holder.getResponse());
request.removeAttribute("__spring_security_scpf_applied");
this.logger.debug("Cleared SecurityContextHolder to complete request");
}
}
SecurityContext contextAfterChainExecution = SecurityContextHolder.getContext();
SecurityContextHolder.clearContext();
this.repo.saveContext(contextAfterChainExecution, holder.getRequest(), holder.getResponse());
request.removeAttribute("__spring_security_scpf_applied");
this.logger.debug("Cleared SecurityContextHolder to complete request");
}
}
我的问题是:显然,在过滤器链完成其工作后,SecurityContextHolder.clearContext()
方法要么在 finally 块中调用,要么在方法结束时调用。但是我知道,我仍然可以在我的控制器和服务层中使用 SecurityContextHolder.getContext()
访问 SecurityContext 对象。如果上面的代码清除了 SecurityContextHolder,那怎么可能呢?我错过了什么吗?
首先,您所指的文档是 spring security 的 4.1.2 版,该版本于 2016 年 12 月 21 日发布。Spring security 当前为 5.6.1,the filter list looks a lot different in the current documentation.
那么上面代码中你的问题的答案是,因为这一行
this.repo.saveContext(contextAfterChainExecution, holder.getRequest(), holder.getResponse());
SecurityContextHolder
是一个单例,所以 SecurityContext
被获取(这将创建一个副本)然后在 singleton
中被清除,最后 this.repo.save
保存下一次的上下文。
这是如何保存的,是不同的,默认情况下相信它使用 HttpSession(这意味着你将获得一个会话 cookie),它在 HttpSessionSecurityContextRepository 中的 Spring 中实现,但你可以设置一个单独的数据库,如果您愿意,可以永久保存它,这样它在重新启动等后仍然存在。