SpringWebFlux 安全性 - 在会话中更新身份验证详细信息

Posted

技术标签:

【中文标题】SpringWebFlux 安全性 - 在会话中更新身份验证详细信息【英文标题】:SpringWebFlux security - update auth details in session 【发布时间】:2021-12-26 05:34:18 【问题描述】:

我正在使用带有 webflux 安全性的 Spring boot 2.5.6。

@EnableWebFluxSecurity
public class AdminSecurityConfig 
          
    @Bean
    public SecurityWebFilterChain securitygWebFilterChain(final ServerHttpSecurity http,
        final ReactiveAuthenticationManager authManager,
        final ServerSecurityContextRepository securityContextRepository,
        final MyAuthenticationFailureHandler failureHandler) 
               
        http.securityContextRepository(securityContextRepository);

        return http.authorizeExchange().matchers(PathRequest.toStaticResources().atCommonLocations()).permitAll()
                        .pathMatchers(props.getSecurity().getIgnorePatterns()).permitAll()
                        .pathMatchers("/api/v1/service/test").hasAuthority("DEFAULT")
                        .anyExchange().authenticated()
                        .and()
                        .formLogin()
                        .loginPage("/login")
                        .authenticationSuccessHandler(authSuccessHandler())
                        .and()
                        .exceptionHandling()
                        .authenticationEntryPoint((exchange, exception) -> Mono.error(exception))
                        .accessDeniedHandler((exchange, exception) -> Mono.error(exception))
                        .and()
                        .build();
            
    
    @Bean
    public PasswordEncoder passwordEncoder() 
        // return new BCryptPasswordEncoder();
        return PasswordEncoderFactories.createDelegatingPasswordEncoder();
    
    
    @Bean
    public ReactiveAuthenticationManager authenticationManager() 
        final UserDetailsRepositoryReactiveAuthenticationManager authenticationManager = new UserDetailsRepositoryReactiveAuthenticationManager(
                    userDetailsService);
        authenticationManager.setPasswordEncoder(passwordEncoder());
        return authenticationManager;
    
    
    @Bean
    public ServerSecurityContextRepository securityContextRepository() 
        final WebSessionServerSecurityContextRepository securityContextRepository = new WebSessionServerSecurityContextRepository();
        securityContextRepository.setSpringSecurityContextAttrName("my-security-context");
        return securityContextRepository;
    

Mono<Principal> principal = ReactiveSecurityContextHolder.getContext().map(SecurityContext::getAuthentication).cast(Principal.class);

final MyAppUserDetails user = (MyAppUserDetails) ((UsernamePasswordAuthenticationToken) principal) .getPrincipal();

在这里我可以检索登录的用户详细信息。 MyAppUserDetails 将包含用户详细信息,例如名字、姓氏、电子邮件、用户 ID、组织 ID、...。 现在,我想在用户登录后更新会话中的用户详细信息,比如更改用户名而不要求用户注销和登录。

我尝试了下面的代码,但不确定如何设置凭据并将更新的用户设置到安全上下文中,以便下一次从安全上下文获取当前用户调用将返回更新的用户。

final MyAppUserDetails appUser = new MyAppUserDetails("firstName", "lastName", "email", 1, 4);
        UsernamePasswordAuthenticationToken authentication  = new UsernamePasswordAuthenticationToken(appUser, ....);
        ReactiveSecurityContextHolder.withAuthentication(authentication);

【问题讨论】:

请发布您的休息端点和请求的样子 下一个调用是什么意思?这些调用是如何实现的? @tmarwen,更新了我的问题 请参阅 AuthenticationWebFilter 以获取有关其在框架内部如何工作的提示。 @SteveRiesenberg 获取会话 --> request.exchange().getSession();更新上下文 --> final SecurityContext context = session.getAttribute("security-context"); context.setAuthentication(token); // 这里是新的令牌。有用。为什么我们需要调用serverSecurityContextRepository.save??? 【参考方案1】:
    从请求中获取会话。 从会话中获取上下文 创建新用户 在上下文中设置新用户
public Mono<ServerResponse> updateSession(ServerRequest request) 
       return request.exchange().getSession().flatMap(session -> 
          final SecurityContext context = session.getAttribute("app-security-context");
          AppUserDetails newUser = AppUserDetails.of(...);
          UsernamePasswordAuthenticationToken token = new UsernamePasswordAuthenticationToken(newUser, pwd, authorities);
          context.setAuthentication(token);
       
    

它正在工作,但不确定为什么我们需要使用以下方法保存上下文。

serverSecurityContextRepository.save(request.exchange(), context);

无需上述调用即可工作。

【讨论】:

如果您阅读WebSessionServerSecurityContextRepository 的javadoc,它提到调用save() 会更改会话ID 以防止会话固定攻击。因为您正在修改会话,所以您应该轮换会话 ID。

以上是关于SpringWebFlux 安全性 - 在会话中更新身份验证详细信息的主要内容,如果未能解决你的问题,请参考以下文章

为啥在 C++ 中更喜欢 char* 而不是字符串?

如何在spring webflux安全中通过绕过选项请求?

`kotlinx.coroutines.withContext` 与 Spring WebFlux 一起使用是不是安全?

Shiro 在 2 分钟后重置会话

Spring webflux 安全性与后端的模拟用户

Spring Webflux + LDAP/Kerberos 安全性