Spring Security之认证信息的处理

前言

在《Spring Security之认证过滤器》中,我们知道认证信息在用户登录成功后,会通过SecurityContextRepository保存。而在《Spring Security之Session管理》中,我们知道SessionManagementConfigurer会创建他。但上面两篇文章都没有仔细说,今天作为主角,咱就好好说道说道,并聊聊与之相关的SecurityContextHolder。

SecurityContextRepository

从名字,我们就知道负责维护SecurityContext。先来看看他的定义:

public interface SecurityContextRepository {
   
   

	/**
	 * 保存安全上下文
	 */
	void saveContext(SecurityContext context, HttpServletRequest request, HttpServletResponse response);

	/**
	 * 从仓库中查询当前请求是否存在上下文
	 */
	boolean containsContext(HttpServletRequest request);
	/**
	 * 从提供的请求中获取SecurityContext。对于未认证的用户,应返回空SecurityContext,而不是null。
	 * HttpRequestResponseHolder参数的作用是允许实现者返回二次封装的request和response,以便访问特定的request或者response(也可以都返回)。
	 * 当最后一次调用的时候,会显式保存SecurityContext,从holder获取的值将被传到过滤器链条和saveContext方法中。
	 * 实现类可能希望返回-当发生错误或者重定向时,确保上下文已经保存的-SaveContextOnUpdateOrErrorResponseWrapper的子类作为response对象。
	 * 实现类可能允许传入原始的request的response来实现显式保存。
	 * @deprecated 请使用#loadDeferredContext(HttpServletRequest)方法代替.
	 */
	@Deprecated
	SecurityContext loadContext(HttpRequestResponseHolder requestResponseHolder);
	/**
	 * 延迟从HttpServletRequest加载SecurityContext,在需要的时候才加载。
	 * 很明显这个方法是前者的代替者。
	 */
	default DeferredSecurityContext loadDeferredContext(HttpServletRequest request) {
   
   
		Supplier<SecurityContext> supplier = () -> loadContext(new HttpRequestResponseHolder(request, null));
		return new SupplierDeferredSecurityContext(SingletonSupplier.of(supplier),
				SecurityContextHolder.getContextHolderStrategy());
	}
}

前面聊session的时候,我们也说过,这个组件有两个实现,一个负责stateless应用,另一个负责stateful应用。我们重点看看后者。

为什么使用Session存储认证信息

我们知道Session也就是会话,会话可以用于维护用户当前一系列操作请求的状态。而我们的认证信息,就是其中的状态之一。他表示用户已经登录,并且是哪个账号在访问系统。但是很显然的是,我们这些信息只能是一个时间段内的,因为我们的账号可能会退出登录态,也就是登出。因此,虽然我们可以在后台数据库中维持这一状态,但是随着用户的退出,我们保存在数据库中的状态,也就不存在任何意义了,浪费空间。
使用Session来存储这一信息,正好符合诉求。需要使用时,直接读取,不用时(退出登录态)自动清除,腾出空间。

但值得注意的是,使用Session需要留意一下,在登录后,通常我们都会重建Session,这可能会导致一些问题。

HttpSessionSecurityContextRepository

/**
 * SecurityContextRepository的一个实现,将安全上下文保存在HttpSession中。
 * 默认情况下,会通过loadContext方法(key: #SPRING_SECURITY_CONTEXT_KEY)从HttpSession中查询获取SecurityContext。
 * 如果不能从HttpSession中获取到一个有效的SecurityContext,则不管是什么原因,都会调用新的SecurityContextHolder#createEmptyContext()方法创建一个新的SecurityContext,并返回该实例。
 * 
 * 当saveContext方法被调用时,上下文将使用同样的key进行保存,为如下场景提供服务:
 * <ol>
 * <li>值变更</li>
 * <li>配置好的AuthenticationTrustResolver不认为该内容代表一个匿名用户</li>
 * </ol>
 * 
 * 在标准配置中,即便是真的不存在HttpSession,loadContext方法也不会创建新的HttpSession。当saveContext在web请求即将结束被调用,只有在传入的SecurityContext不是一个空的SecurityContext实例时,才会创建一个新的HttpSession。这能够避免不必要的HttpSession的创建,但会自动存储请求期间对上下文所做的变更。
 * 注意:如果SecurityContextPersistenceFilter配置了提前HttpSession,那么session最小化的逻辑将不再生效。
 * 如果你使用急切的session创建方式,那么你应该确保这个类的allowSessionCreation属性设置为true(默认)。
 * <p>
 * 如果由于某些原因(例如,使用Basic认证方式或者多个类似的客户端永远不会出现相同的jsessionid的情况)导致HttpSession没有被创建,那么应当通过#setAllowSessionCreation(boolean)将allowSessionCreation属性设置为false。
 * 只有你真正需要节省服务器内存时,并确保所有使用SecurityContextHolder的类,都被设计成:在不同的web请求之间都不需要持久化的SecurityContext时,你才能这样做。
 * @since 3.0
 */
public class HttpSessionSecurityContextRepository implements SecurityContextRepository
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值