在Spring Webflux中注册后自动登录用户

时间:2020-07-22 09:22:25

标签: spring spring-security spring-webflux

我有一个Spring WebFlux应用程序,其中登录和注册功能都运行良好。登录已使用UserDetailsService进行了实现,其中我们有一个扩展UserDetails的域类和一个@Service,它知道如何找到给定用户名的用户。

尽管注册流程有效,但用户需要在注册后立即登录,而不是在注册后直接登录。

我的问题是,Spring是否提供类似login的方法,该方法采用UserDetails对象,并设置会话以使该用户登录?如果没有,我可以从哪里开始实现这样的指示?

对于上下文:在研究到深入挖掘spring-security的源代码并变空之后,我将发布此问题。

非常感谢您的宝贵时间。

编辑:Spring安全性登录页面配置:

.and().formLogin()
                .loginPage(Url.LOGIN_URL)
                .authenticationEntryPoint(authenticationEntryPoint)
                .requiresAuthenticationMatcher(ServerWebExchangeMatchers.pathMatchers(HttpMethod.POST, Url.LOGIN_URL))
                .authenticationSuccessHandler(authenticationSuccessHandler)
                .authenticationFailureHandler(authenticationFailureHandler)

2 个答案:

答案 0 :(得分:2)

  • 我不了解webflux,但今天早上我想试一试,如果这不是webflux中的工作方式,请放轻松。我只是拿了一个示例应用程序,添加了sign-up/{newUserName}端点,它不仅会注册用户,还会登录。
    @GetMapping("/sign-up/{newUserName}")
    public Mono<String> signUp(@PathVariable("newUserName") String userName, 
                               ServerWebExchange exchange) {
        UserDetails newUser = User.withDefaultPasswordEncoder()
                .username(userName)
                .password("password")
                .roles("USER")
                .build();
        customMapReactiveUserDetailsService.addNewUser(newUser);

        return exchange.getSession()
                .doOnNext(session -> {
                    SecurityContextImpl securityContext 
                                    = new SecurityContextImpl();
                    UsernamePasswordAuthenticationToken authentication
                        = new UsernamePasswordAuthenticationToken(userName, 
                                   null, newUser.getAuthorities());
                    securityContext.setAuthentication(authentication);
                    
                    session.getAttributes()
                        .put(DEFAULT_SPRING_SECURITY_CONTEXT_ATTR_NAME, 
                             securityContext);
                })
                .flatMap(WebSession::changeSessionId)
                .then(Mono.just("You can now go to /secured without login"));
    }

    @Configuration
    @EnableWebFluxSecurity
    public class SecurityConfiguration {

       @Bean
       public SecurityWebFilterChain securityWebFilterChain(ServerHttpSecurity http) 
       {
          return http.authorizeExchange()
                .pathMatchers("/secured").hasRole("USER")
                .anyExchange().permitAll()
                .and().httpBasic()
                .and().build();
        }

        @Bean
        public CustomMapReactiveUserDetailsService userDetailsService() {
           // There are no registered users at this point
          Map<String,  UserDetails> users = new HashMap<>();
          return new CustomMapReactiveUserDetailsService(users);
        }
     }
  • 注册非常简单,因为它不是此演示的目的,而是通过GET http://localhost:8080/sign-up/{newUserName}完成的。

  • 将创建一个新用户,用户名为newUserName,密码为password,角色为USER,该用户已添加到注册用户的地图中。

  • 我认为只有这一点对您的问题很重要。正常登录时,如果登录成功,AuthenticationWebFilter将调用securityContextRepository.save(exchange, securityContext)保存上下文。但是对于请求过滤器来说为时已晚,因为我现在在注册控制器中,因此我只是在控制器方法中复制该行为以进行注册。但这可以在仅适用于sign-up/{newUserName}的Web过滤器的响应路径中完成,但我对webflux过滤器机制并不熟悉。这是因为在sign-up/{newUserName}的响应路径上,您将知道注册是否成功,并且该用户当时已经存在于数据库中,因此它仅是复制登录行为。

  • Github存储库

    https://github.com/kavi-kanap/stackoverflow-63030967

更新

答案 1 :(得分:1)

从您的评论看来,您似乎正在使用Redis来存储会话,但是在登录配置中未指定.securityContextRepository(),您应该指定一个以便在redis中存储会话(这是询问您的第一个问题)。

要自动登录用户,您可以执行以下操作:

  1. 当您拥有SPA应用程序时,可以在AuthenticationSuccessHandler中(我想您正在生成会话ID,如果不是这样的话,也没有问题),则可以将用户重定向到家中,然后您的前端路由器可以将用户重定向到您想要在注册帐户时将用户重定向到的页面(组件),您可以手动执行此操作或通过RedirectServerAuthenticationSuccessHandler

  2. 当您到达该页面(组件)时,您可以(通过后端)检查用户是否在cookie中存储了有效的会话;如果是,则显示所有内容;否则,显示警告或重定向到首页像这样的东西。