Search code examples
springspring-bootspring-securityspring-webfluxspring-bean

Spring different implementations of one service in controller depended on authenticated user's authority


I have a ReservationController in my spring project that injects ReservationService. Here is my ReservationController Class

I have two implementations of ReservationService: ReservationServiceImpl and ReservationDoublePriceServiceImpl. Here is my ReservationService1 Class

Here is my ReservationService2 Class

I want ReservationController to choose service's implementation depended on authenticated user's authority(If authority is User choose ReservationServiceImpl and if authority is DoublePriceUser choose ReservationDoublePriceServiceImpl).

Can someone suggest how can I do this?

P.S I have done with application.properties parameter and qualifiers, but it only makes me an opportunity to choose only one of my service implementations.

How can I choose service beans in Runtime?


Solution

  • There are plenty ways to do that, I'd suggest to start with something simple. Add a supports(Set<String> authorities) method in your ReservationService interface, and the implementation itself will tell if it supports the authorities passed (check if contains the role).

    Create a Factory class, which will be used to choose the right implementation for you, like so:

    @Component
    public class ReservationServiceFactory {
    
        private final List<ReservationService> services;
    
        public ReservationService getService(Set<String> authorities) {
            for (ReservationService service : this.services) {
                if (service.supports(authorities)) {
                    return service;
                }
            }
            throw new IllegalArgumentException("Could not resolve ReservationService for authorities " + authorities);
        }
    
    }
    
    public interface ReservationService {
        // add this method in your ReservationService interface
        boolean supports(Set<String> authorities);
    }
    

    And, in your controller you can do something like:

    @GetMapping
    public void anyMethod(/*inject the authentication object*/Authentication authentication) {
        this.reservationServiceFactory.getService(authentication.getAuthorities()).doSomething();
    }