Функция внутри .map выполняется дважды - PullRequest
0 голосов
/ 17 марта 2020

Я пытаюсь создать сервис аутентификации на весенней загрузке 2.2.5. RELEASE, с реактивным стеком. Я почесал голову с тех пор, как часы.

Функция внутри .map выполняется дважды.

@Override
    public Mono<UserDetails> findByUsername(final String userName) {
        System.out.println("findByUsername called");
        return Mono.fromSupplier(() -> userRepository.findByUsername(userName)).subscribeOn(SCHEDULER)
            .switchIfEmpty(Mono.error(new UsernameNotFoundException("Bad credentials")))
            .map(user -> {
                System.out.println("inside findByUsername");
                new AccountStatusUserDetailsChecker().check(user);
                return (UserDetails)user;
        }).log();
    }

Ниже приведен нереактивный репо postgres (таким образом, поставщик в приведенном выше коде).

@Repository
@Transactional
public interface UserRepository extends JpaRepository<User, Long> {

    /**
     * Finds a user by username
     *
     * @param username user's name
     * @return user object
     */
    User findByUsername(String username);
}

Ниже вызывается функция findByUsername:

@Override
    public Mono<SecurityContext> load(ServerWebExchange swe) {
        System.out.println("load called");
        final ServerHttpRequest request = swe.getRequest();
        final String username = request.getHeaders().getFirst(CustomHTTPHeaders.Keys.USERNAME);
        final String password = request.getHeaders().getFirst(CustomHTTPHeaders.Keys.PASSWORD);
        final AbstractAuthenticationToken auth = new UsernamePasswordAuthenticationToken(username, password);
        return userDetailService.findByUsername(username).map(details -> {
            System.out.println("isnide flatmap " + Thread.currentThread().getName());
            auth.setDetails(details);
            SecurityContext securityContext =  SecurityContextHolder.getContext();
            if(passwordEncoder.matches(auth.getCredentials().toString(), details.getPassword())) {
                securityContext.setAuthentication(new UsernamePasswordAuthenticationToken(details.getUsername(), details.getPassword(), details.getAuthorities()));
                return securityContext;
            }
            securityContext.setAuthentication(new UsernamePasswordAuthenticationToken(details.getUsername(), null));
            return securityContext;
        });

Вывод:

load called
findByUsername called
2020-03-17 20:04:58.281  INFO 44648 --- [oundedElastic-3] reactor.Mono.Map.1     : onSubscribe(FluxMap.MapSubscriber)
2020-03-17 20:04:58.283  INFO 44648 --- [oundedElastic-3] reactor.Mono.Map.1     : request(unbounded)
inside findByUsername
2020-03-17 20:04:58.466  INFO 44648 --- [oundedElastic-4] reactor.Mono.Map.1     : onNext(User(email=william@gmail.com, username=admin, password={bcrypt}$2a$10$EOs8VROb14e7ZnydvXECA.4LoIhPOoFHKvVF/iBZ/ker17Eocz4Vi, enabled=true, accountLocked=false, accountExpired=false, credentialsExpired=false, roles=[Role(name=role_admin, permissions=[Permission(name=CREATE_USER), Permission(name=UPDATE_USER), Permission(name=READ_USER), Permission(name=DELETE_USER), Permission(name=VERIFY_TOKEN)])]))
isnide flatmap boundedElastic-4
2020-03-17 20:04:58.598  INFO 44648 --- [oundedElastic-4] reactor.Mono.Map.1     : cancel()
2020-03-17 20:04:58.604  INFO 44648 --- [oundedElastic-4] reactor.Mono.Map.1     : onSubscribe(FluxMap.MapSubscriber)
2020-03-17 20:04:58.604  INFO 44648 --- [oundedElastic-4] reactor.Mono.Map.1     : request(unbounded)
inside findByUsername
2020-03-17 20:04:58.608  INFO 44648 --- [oundedElastic-3] reactor.Mono.Map.1     : onNext(User(email=william@gmail.com, username=admin, password={bcrypt}$2a$10$EOs8VROb14e7ZnydvXECA.4LoIhPOoFHKvVF/iBZ/ker17Eocz4Vi, enabled=true, accountLocked=false, accountExpired=false, credentialsExpired=false, roles=[Role(name=role_admin, permissions=[Permission(name=CREATE_USER), Permission(name=UPDATE_USER), Permission(name=READ_USER), Permission(name=DELETE_USER), Permission(name=VERIFY_TOKEN)])]))
isnide flatmap boundedElastic-3
2020-03-17 20:04:58.716  INFO 44648 --- [oundedElastic-3] reactor.Mono.Map.1     : onComplete()

WebSecurityConfig:

package com.turtlemint.authservice.config;

import com.turtlemint.authservice.controller.SecurityContextRepository;
import com.turtlemint.authservice.service.impl.AuthenticationManager;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.http.HttpMethod;
import org.springframework.http.HttpStatus;
import org.springframework.security.config.annotation.method.configuration.EnableReactiveMethodSecurity;
import org.springframework.security.config.annotation.web.reactive.EnableWebFluxSecurity;
import org.springframework.security.config.web.server.ServerHttpSecurity;
import org.springframework.security.crypto.factory.PasswordEncoderFactories;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.server.SecurityWebFilterChain;
import reactor.core.publisher.Mono;

/**
 * <p>
 *      This class holds spring security configuration
 * </p>
 *
 * @author praveenkamath
 * created on 09/03/20
 * @since 1.0.0
 */
@EnableWebFluxSecurity
@EnableReactiveMethodSecurity
public class WebSecurityConfiguration {

    @Autowired
    AuthenticationManager authenticationManager;

    @Autowired
    private SecurityContextRepository securityContextRepository;

    /**
     * Provides a password encoder
     *
     * @return password encoder instance
     */
    @Bean
    public PasswordEncoder passwordEncoder() {
        return PasswordEncoderFactories.createDelegatingPasswordEncoder();
    }

    /**
     * Configures end-points for security
     *
     * @param http http security
     */
    @Bean
    public SecurityWebFilterChain securityWebFilterChain(final ServerHttpSecurity http) {
        return http.cors().disable()
                .exceptionHandling()
                .authenticationEntryPoint((swe, e) -> Mono.fromRunnable(() -> {
                    swe.getResponse().setStatusCode(HttpStatus.UNAUTHORIZED);
                })).accessDeniedHandler((swe, e) -> Mono.fromRunnable(() -> {
                    swe.getResponse().setStatusCode(HttpStatus.FORBIDDEN);
                })).and()
                .csrf().disable()
                .authenticationManager(authenticationManager)
                .securityContextRepository(securityContextRepository)
                .authorizeExchange()
                //.pathMatchers("/api/**").permitAll()
                .pathMatchers(HttpMethod.OPTIONS).permitAll()
                .anyExchange().authenticated()
                .and()
                .build();

    }
}

Не знаю, является ли это ошибкой в ​​реакторе проекта или в моем коде. Пожалуйста, помогите.

...