美文网首页
SpringSecurity如何设置和修改登录态

SpringSecurity如何设置和修改登录态

作者: 李昂的数字之旅 | 来源:发表于2023-04-01 00:44 被阅读0次

    登录态存储形式

    使用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维护的登录态也会同步更新。

    相关文章

      网友评论

          本文标题:SpringSecurity如何设置和修改登录态

          本文链接:https://www.haomeiwen.com/subject/earkddtx.html