1

I have a request method that use 'username' and 'password' body parameters to find real user from database, validate it by using request password and if everything is fine - return generated token as String.

public Mono<ServerResponse> handleLogin(ServerRequest request) {
    User body = request.bodyToMono(User.class).block();
    return userRepository.findById(body.getUsername())
            .filter(user -> passwordEncoder.matches(body.getPassword(), user.getPassword()))
            .flatMap(user -> ServerResponse.ok().body(Mono.just(tokens.store(user)), String.class))
            .switchIfEmpty(ServerResponse.badRequest().build());
}

This method works fine, but i'm trying to make it as non-blocking and i'm not sure how to achieve it. Any help appreciated.

Updated

For now i changed my method content to

    return request.bodyToMono(User.class)
            .flatMap(body -> userRepository.findById(body.getUsername()).flatMap(user -> Mono.just(new Object[]{body.getPassword(), user})))
            .filter(obj -> {
                User user = (User) obj[1];
                return user.isActive() && passwordEncoder.matches((CharSequence) obj[0], user.getPassword());
            })
            .flatMap(obj -> {
                User user = (User) obj[1];
                return ServerResponse.ok().body(Mono.just(tokens.store(user)), String.class);
            })
            .switchIfEmpty(ServerResponse.badRequest().build());

This is non-blocking, but looks like not so elegant solution. Can it be improved/simplified somehow?

1 Answer 1

2

Remember

1) Everything is stream.

2) Keep your flow composed

3) No blocking operation at all.

Solution

So, keep your flow composed without blocking operation

public Mono<ServerResponse> handleLogin(ServerRequest request) {

    return request.bodyToMono(User.class)
                  .flatMap(body -> userRepository.findById(body.getUsername())
                  .filter(user -> passwordEncoder.matches(body.getPassword(), user.getPassword()))
                  .flatMap(user -> ServerResponse.ok().body(Mono.just(tokens.store(user)), String.class))
                  .switchIfEmpty(ServerResponse.badRequest().build());
}

Regarding the last update

Regarding the last update, from my point of view, the code might be optimized in a next way:

return request.bodyToMono(User.class)
            .flatMap(body -> userRepository.findById(body.getUsername())                              
                                           .filter(user -> user.isActive())
                                           .filter(user -> passwordEncoder.matches(body.getPassword(), user.getPassword()))
            )
            .flatMap(user -> ServerResponse.ok().syncBody(tokens.store(user)))
            .switchIfEmpty(ServerResponse.badRequest().build());
Sign up to request clarification or add additional context in comments.

1 Comment

In this case .filter(user -> passwordEncoder.matches(body.getPassword(), user.getPassword())) don't know the body, so body.getPassword() will not work here. I need somehow to pass the password parameter from user request to use it inside filter.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.