Имитируйте, что клиент создает неавторизованное исключение для URL-адреса, где аутентификация не требуется

Я следил за этим блогом и создали несколько микросервисов: Eureka-server, Auth-service, Zuul-service, Gallery-service, Image-service. Из службы галереи я хотел вызвать API службы аутентификации с помощью Feign-Client. URL-адрес не требует аутентификации, но клиент выдает FeignException $ Unauthorized. Я использую токены JWT для аутентификации.

//AuthServerProxy.java

@FeignClient(name = "auth-service")
@RibbonClient(name = "auth-service")
public interface AuthServiceProxy {

    @PostMapping("/auth/authenticate")
    public ResponseEntity<?> authenticate(@RequestBody UserEntity userEntity);

    @GetMapping("/auth/register")
    public String test();
}

Контроллер - Служба галереи

@Autowired
    AuthServiceProxy authServiceProxy;
    @GetMapping("/test")
    public String test(){
        UserEntity userEntity = new UserEntity();
        userEntity.setUsername("admin");
        userEntity.setPassword("admin");
        ResponseEntity<?> responseEntity = authServiceProxy.authenticate(userEntity);
        System.out.println(responseEntity.getStatusCode());
        return responseEntity.toString();

    }

    @GetMapping("/test/str")
    public String testStr(){
        return authServiceProxy.test();
    }

Конфигурация безопасности - ZuulServer, Auth-Service

.antMatchers(HttpMethod.POST, "/auth/authenticate").permitAll()

Это журнал ошибок

ERROR 1123 --- [nio-8100-exec-1] o.a.c.c.C.[.[.[/].[dispatcherServlet]    : Servlet.service() for servlet [dispatcherServlet] in context with path [] threw exception [Request processing failed; nested exception is feign.FeignException$Unauthorized: status 401 reading AuthServiceProxy#authenticate(UserEntity)] with root cause

feign.FeignException$Unauthorized: status 401 reading AuthServiceProxy#authenticate(UserEntity)
at feign.FeignException.errorStatus(FeignException.java:94) ~[feign-core-10.2.3.jar:na]
    at feign.FeignException.errorStatus(FeignException.java:86) ~[feign-core-10.2.3.jar:na]
    at feign.codec.ErrorDecoder$Default.decode(ErrorDecoder.java:93) ~[feign-core-10.2.3.jar:na]
    at feign.SynchronousMethodHandler.executeAndDecode(SynchronousMethodHandler.java:149) ~[feign-core-10.2.3.jar:na]
    at feign.SynchronousMethodHandler.invoke(SynchronousMethodHandler.java:78) ~[feign-core-10.2.3.jar:na]
    at feign.ReflectiveFeign$FeignInvocationHandler.invoke(ReflectiveFeign.java:103) ~[feign-core-10.2.3.jar:na]
    at com.sun.proxy.$Proxy101.authenticate(Unknown Source) ~[na:na]
    at com.test.gallery.Controller.test(Controller.java:47) ~[classes/:na]
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.8.0_201]
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) ~[na:1.8.0_201]
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.8.0_201]
    at java.lang.reflect.Method.invoke(Method.java:498) ~[na:1.8.0_201]
    at org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:190) ~[spring-web-5.1.9.RELEASE.jar:5.1.9.RELEASE]
    at org.springframework.web.method.support.InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:138) ~[spring-web-5.1.9.RELEASE.jar:5.1.9.RELEASE]
    at org.springframework.web.servlet.mvc.method.annotation.ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:104) ~[spring-webmvc-5.1.9.RELEASE.jar:5.1.9.RELEASE]
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:892) ~[spring-webmvc-5.1.9.RELEASE.jar:5.1.9.RELEASE]
    at org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:797) ~[spring-webmvc-5.1.9.RELEASE.jar:5.1.9.RELEASE]
    at org.springframework.web.servlet.mvc.method.AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:87) ~[spring-webmvc-5.1.9.RELEASE.jar:5.1.9.RELEASE]
    at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1039) ~[spring-webmvc-5.1.9.RELEASE.jar:5.1.9.RELEASE]
    at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:942) ~[spring-webmvc-5.1.9.RELEASE.jar:5.1.9.RELEASE]
    at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1005) ~[spring-webmvc-5.1.9.RELEASE.jar:5.1.9.RELEASE]
    at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:897) ~[spring-webmvc-5.1.9.RELEASE.jar:5.1.9.RELEASE]
...

Любая помощь очень ценится. TIA


person Harsha Sridhar    schedule 28.10.2019    source источник
comment
Вы уверены, что Feign вызывает правильный URL? Можете ли вы включить логи и проверить это? Можете ли вы получить доступ к этому URL-адресу через веб-браузер или клиент Postman?   -  person Piszu    schedule 29.10.2019
comment
Да, я могу получить доступ к URL-адресу через Advanced Rest Client, но он не работает при доступе через Feign Client   -  person Harsha Sridhar    schedule 30.10.2019


Ответы (3)


Похоже, заголовок аутентификации не проходит с FeignClient

попробуйте добавить этот конфиг:

@Bean
public RequestInterceptor requestInterceptor() {

    return requestTemplate -> {
        Authentication authentication = SecurityContextHolder.getContext().getAuthentication();

        if (authentication != null && authentication.getDetails() instanceof OAuth2AuthenticationDetails) {
            OAuth2AuthenticationDetails details = (OAuth2AuthenticationDetails) authentication.getDetails();
            requestTemplate.header(HttpHeaders.AUTHORIZATION, String.format("Bearer %s", details.getTokenValue()));
        }
    };
}
person Jay    schedule 10.08.2020

Feign не знает об авторизации, которая должна быть передана целевой службе. К сожалению, вам нужно справиться с этим самостоятельно. Ниже приведен класс java, который может помочь.

@Component
public class FeignClientInterceptor implements RequestInterceptor {

     private static final String AUTHORIZATION_HEADER = "Authorization";
       private static final String BEARER_TOKEN_TYPE = "Bearer";
    
    
       @Override
        public void apply(RequestTemplate template) {
            SecurityContext securityContext = SecurityContextHolder.getContext();
            Authentication authentication = securityContext.getAuthentication();

            if (authentication != null && authentication.getDetails() instanceof OAuth2AuthenticationDetails) {
                OAuth2AuthenticationDetails details = (OAuth2AuthenticationDetails) authentication.getDetails();
                template.header(AUTHORIZATION_HEADER, String.format("%s %s", BEARER_TOKEN_TYPE, details.getTokenValue()));
            }
        }
person ayman.mostafa    schedule 17.08.2020

Похоже, проблема может заключаться в том, что у вас нет @EnableResourceServer, подключенного к вашей Auth-Service.

Без этой аннотации любая конечная точка, не входящая в состав пакета безопасности spring (например, / oauth / token, / oauth / check_token), автоматически потребует авторизации.

Кроме того, вам может потребоваться добавить ResourceServerConfigurerAdapter, подобный этому, чтобы убедиться, что конечные точки ресурсов настроены так, чтобы разрешать все, например:

@Configuration
@EnableResourceServer
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {

    private final TokenStore tokenStore;

    public ResourceServerConfig(TokenStore tokenStore) {
        this.tokenStore = tokenStore;
    }

    @Override
    public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
        resources.tokenStore(tokenStore);
    }

    @Override
    public void configure(HttpSecurity http) throws Exception {
        http
                .authorizeRequests()
                .antMatchers(HttpMethod.POST).permitAll()
                .and()
                .logout().disable()
                .csrf().disable();
    }
}

*******РЕДАКТИРОВАТЬ*********

Если вы можете получить нормальный ответ на запрос в браузере, но не симулируете, то ваша проблема, скорее всего, в том, что ваш клиент Feign не указывает на правильную конечную точку. Обычно вы ожидаете ошибки 404, но поскольку API защищен, вы получаете 401, потому что он даже не позволяет вам узнать, какая конечная точка является действительной, если вы не прошли аутентификацию или это незащищенная конечная точка.

Если у вас есть воображаемый клиент AuthServiceProxy, использующий ваш zuul-сервер вместо auth-service, вы можете добавить ведение журнала в свой фильтр zuul, чтобы увидеть, как выглядят как успешные, так и неудачные запросы. Оттуда внесите необходимые изменения, чтобы ваш прокси-запрос соответствовал запросу, который вы сделали из браузера, и все должно быть в порядке.

person magicjedi90    schedule 29.10.2019
comment
У меня нет сервера ресурсов, и я предполагаю, что для него нужно добавить некоторые зависимости. Это ссылка на репозиторий GitHub: github.com/harshasridhar/microservice-example Пожалуйста, сделайте Предложите мне изменения, которые необходимо внести. Я сделал еще один URL-адрес GET / auth / register в auth-service, при доступе из браузера без токена он работает, но из Feign Client он по-прежнему выдает несанкционированное исключение - person Harsha Sridhar; 30.10.2019
comment
Я изменил клиент симуляции прокси, чтобы использовать zuul-сервер, и поток запросов показан на изображении! Изображение Понятия не имею, почему zuul-сервер перенаправляет на / ошибку auth-service - person Harsha Sridhar; 04.11.2019
comment
Даже когда прокси использует службу аутентификации, выполняется вызов / error - person Harsha Sridhar; 04.11.2019
comment
У вас есть сервер Eureka? Я спрашиваю, потому что в вашем репозитории git нет сервера имен, а ваша служба галереи application.properties ожидает, что он будет на localhost: 8761 - person magicjedi90; 05.11.2019
comment
Да, у меня запущен сервер Eureka. Я не добавлял код сервера в репо, так как повторно использовал код из другого проекта, только для сервера eureka - person Harsha Sridhar; 05.11.2019
comment
После некоторой отладки я обнаружил, что запрос / auth / register действительно достиг службы auth и между исключением java.io.IOException: выбрасывается сломанный канал, который затем перенаправляет запрос на / error. Понятия не имею, почему это происходит. - person Harsha Sridhar; 06.11.2019
comment
Поэтому я не уверен, что идет не так, но попробуйте вместо этого использовать этот учебник: itnext.io/ Он использует хранилище токенов вместо jwt, но он должен помочь вам как минимум наладить связь между вашими микросервисами. - person magicjedi90; 07.11.2019