2

Я экспериментирую с тремя приложениями Spring Cloud (boot).Как запустить аутентификацию OAuth2 в шлюзе API Zuul, если служба нисходящего потока отвечает 401

  1. аутентификация сервер на порту 9999
  2. Основного бэкенда-образец, который обеспечил и необеспеченные конечные точки на порту 9008
  3. Основного Zuul шлюз API, с несколькими маршрутами (обеспеченный и необеспеченный) к серверному-образцу порт загрузки приложения 9000

бэкэнд-образец аннотированные в качестве сервера ресурсов (@EnableResourceServer) и обеспечивает некоторые конечные точки с ResourceServerConfigurerAdapter

Когда я впервые вызываю один из маршрутов, защищенных на шлюзе API Zuul, я перенаправляюсь на страницу входа в сервер аутентификации. После входа в систему я перенаправляюсь на защищенный маршрут, который я изначально запросил. Охваченные конечные точки бэкэнда-образца ведут себя так, как ожидалось, что означает, что бэкэнд-образец получает предоставленные роли для поставленного токена. Если я удаляю конечную точку бэкэнда-образца, для которой у меня нет надлежащей роли, я получаю ответ OAuth 403. В этом случае все в порядке.

Нам также нужно разместить устаревшие службы за шлюзом API. Они отображают html и должны иметь возможность запускать логин, когда пользователь попадает в защищенную зону. Мы не можем защитить эти области от уровня маршрута шлюза API, поскольку у старых бэкендов есть сложные (выращенные) модели разрешений для многих разных URL-адресов.

Кто-нибудь знает, как сделать шлюз API-интерфейса Spring-cloud перенаправлен на логин сервера аутентификации в таком случае с 401-ответным ответом ниже по потоку? Я попробовал простую переадресацию в ZuulFilter типа post, но не смог, поскольку ответ уже был зафиксирован там.

Backend-sample application.yml;

server: 
 
    port: 9008 
 
    
 
security: 
 
    oauth2: 
 
    resource: 
 
     userInfoUri: http://localhost:9999/uaa/user

API шлюза application.yml:

server: 
    port: 9008 
zuul: 
    proxy: 
     addProxyHeaders: true 
    sensitive-headers: 
    routes: 
     unsecured-backend-sample: 
     path: /unsecured-backend-sample/** 
     url: http://localhost:9008 
     authorized-backend-sample: 
     path: /authorized-backend-sample/** 
     url: http://localhost:9008/ 
     user-role-secured-backend-sample: 
     path: /user-role-secured-backend-sample/** 
     url: http://localhost:9008/ 
     xxx-role-secured-backend-sample: 
     path: /xxx-role-secured-backend-sample/** 
     url: http://localhost:9008/ 
security: 
    oauth2: 
    client: 
     accessTokenUri: http://localhost:9999/uaa/oauth/token 
     userAuthorizationUri: http://localhost:9999/uaa/oauth/authorize 
     clientId: acme 
     clientSecret: acmesecret 
    resource: 
     userInfoUri: http://localhost:9999/uaa/user 
+0

ли ваш постфильтр работать до или после SendResponseFilter? – spencergibb

+0

Спасибо, что посмотрели Спенсер. Я думаю, что моя первоначальная попытка была после SendResponseFilter, когда уже слишком поздно. Я нашел решение ZuulFilter и опубликую его здесь в качестве ответа. Было бы здорово, если бы вы могли прокомментировать это. Если вам это нравится, и я думаю, что он совместим с архитектурными концепциями весеннего облака, я бы хотел это сделать. –

ответ

2

я, наконец, нашел решение, которое отлично работает для меня. Я написал ZuulFilter, который обрабатывает только 401 ответ и перенаправляет логин. Он также сохраняет отклоненный запрос в кеше запросов сеанса HTTP, поэтому SavedRequestAwareAuthenticationSuccessHandler может перенаправить вас обратно к первоначально запрошенному URL-адресу нисходящей службы.

@Component 
public class LoginOnDownstreamUnauthorizedResponseFilter extends ZuulFilter { 

    private Logger logger = LoggerFactory.getLogger(getClass()); 

    private AuthenticationEntryPoint authenticationEntryPoint = new LoginUrlAuthenticationEntryPoint("/login"); 

    private RequestCache requestCache = new HttpSessionRequestCache(); 

    @Override 
    public boolean shouldFilter() { 
     // Only handle downstream 401s 
     return RequestContext.getCurrentContext().getResponse().getStatus() == HttpStatus.SC_UNAUTHORIZED; 
    } 

    @Override 
    public Object run() { 

     RequestContext ctx = RequestContext.getCurrentContext(); 
     HttpServletRequest request = ctx.getRequest(); 
     HttpServletResponse response = ctx.getResponse(); 

     // We need to put the rejected request in the request cache for SavedRequestAwareAuthenticationSuccessHandler 
     // to find it's way back to the initial request URI after successful authentication. 
     requestCache.saveRequest(request, response); 

     String text = String.format("Downstream service %s responded with a status code 401.", request.getRequestURI()); 
     logger.debug(text + " Calling Authentication entry point."); 
     try { 
      authenticationEntryPoint.commence(request, response, new InsufficientAuthenticationException(text)); 
     } catch (IOException | ServletException e) { 
      logger.error("Failed to redirect to Authentication entry point", e); 
     } 

     return null; 
    } 

    @Override 
    public String filterType() { 
     return "post"; 
    } 

    @Override 
    public int filterOrder() { 
     // make sure to run before SendResponseFilter 
     return 500; 
    } 

}