SpringSecurity如何设置和修改登录态

登录态存储形式

使用Spring Security框架,用户认证成功后的用户信息会放在Authentication 对象的Principal中。Authentication 对象又会放入SecurityContext ,而SecurityContext 存在这2个地方:

  1. SecurityContextHolderStrategy :线程级别的SecurityContext持有策略。有全局共享、线程继承、线程隔离等几种获取上下文的方式。
  2. SecurityContextRepository:持久化SecurityContext ,默认存入HttpServletRequestHttpSession

在代码中,我们要获取用户登录信息,可以通过SecurityContextHolder.*getContext*().getAuthentication() 的方式获取,这种方式是从SecurityContextHolderStrategy获取用户数据。而SecurityContextHolderStrategy初始化数据又是来自SecurityContextRepository,相关逻辑是在SecurityContextHolderFilter 类里。

设想一种场景,在用户登录后,编辑了用户信息,这时要同步刷新SecurityContext里的用户信息。我们要如何更新这两个处的用户数据呢?

更新SecurityContextHolderStrategy 中的用户信息

要更新SecurityContextHolderStrategy非常简单,因为它保存在内存里,只要通过SecurityContextHolder.*getContext*().getAuthentication() 获取认证信息后,直接设置对应的属性,内存中属性值发生变化,后续处理逻辑就能读到最新值。

Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
MyUser myUser = (MyUser) authentication.getPrincipal();
myUser.setNickname("新的昵称");

更新SecurityContextRepository中的用户信息

无法直接获取SecurityContextRepository对象

要知道怎么更新SecurityContextRepository ,我们先看其他地方是怎么调用它。往SecurityContextRepository 写数据是在用户认证成功之后,调用AbstractAuthenticationProcessingFilter#successfulAuthentication() 方式执行认证成功的后续逻辑时。

protected void successfulAuthentication(HttpServletRequest request, HttpServletResponse response, FilterChain chain,
			Authentication authResult) throws IOException, ServletException {
		SecurityContext context = this.securityContextHolderStrategy.createEmptyContext();
		context.setAuthentication(authResult);
		this.securityContextHolderStrategy.setContext(context);

		// 这里写入securityContextRepository
		this.securityContextRepository.saveContext(context, request, response);

		...
	}

这里的this.securityContextRepository是通过setter方法传进来的,并且发现Spring Security没有把SecurityContextRepository 注册到Spring容器,而且Spring Security其他持有SecurityContextRepository 对象的类都没有暴露SecurityContextRepository 的获取方法。也就是说,我们无法从Spring Security拿到默认的SecurityContextRepository 对象。

手动设置SecurityContextRepository对象

为了顺利拿到SecurityContextRepository对象,我们可以手动往Spring容器注册一个SecurityContextRepository对象,然后把它塞到Spring Security里。通过这种方式,我们能从Spring容器拿到SecurityContextRepository 对象,然后随时刷新SecurityContext

Spring Security设置SecurityContextRepository 的方式是:

@Bean
public SecurityContextRepository securityContextRepository() {
    return new DelegatingSecurityContextRepository(
            new RequestAttributeSecurityContextRepository(), new HttpSessionSecurityContextRepository());
}

@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity httpSecurity, SecurityContextRepository securityContextRepository) throws Exception {
	httpSecurity
        .securityContext(it -> it.securityContextRepository(securityContextRepository))
	return httpSecurity.build();
}

这里DelegatingSecurityContextRepository是Spring Security的默认值,我们原封不动保留下来。

更新登录态

在更新完SecurityContextHolderStrategy 对象之后,我们把SecurityContext 重新保存到SecurityContextRepository

// 更新SecurityContextHolderStrategy
Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
MyUser myUser = (MyUser) authentication.getPrincipal();
myUser.setNickname("新的昵称");

// 更新SecurityContextRepository
securityContextRepository.saveContext(SecurityContextHolder.getContext(), request, response);

总结

通过更新SecurityContextHolderStrategySecurityContextRepository ,我们就能完整更新SecurityContext 中的用户信息。如果项目中引入了Spring Session,Spring Session维护的登录态也会同步更新。

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

李昂的数字之旅

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

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

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

打赏作者

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

抵扣说明:

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

余额充值