Adicionar suporte de CORS a um proxy de API

Esta página aplica-se ao Apigee e ao Apigee Hybrid.

Veja a documentação do Apigee Edge.

A partilha de recursos de origem cruzada (CORS) é um mecanismo padrão que permite que as chamadas JavaScript XMLHttpRequest (XHR) executadas numa página Web interajam com recursos de domínios não originais. A CORS é uma solução implementada frequentemente para a política de mesma origem que é aplicada por todos os navegadores. Por exemplo, se fizer uma chamada XHR à API Twitter a partir de código JavaScript em execução no seu navegador, a chamada falha. Isto deve-se ao facto de o domínio que publica a página no seu navegador não ser o mesmo que o domínio que publica a API do Twitter. O CORS oferece uma solução para este problema, permitindo que os servidores optem por partilhar recursos de origem cruzada, se assim o desejarem.

Exemplo de utilização típico da CORS

O código JQuery seguinte chama um serviço de destino fictício. Se for executado a partir do contexto de um navegador (uma página Web), a chamada falha devido à política de mesma origem:

<script>
var url = "http://service.example.com";
$(document).ready(function(){
  $("button").click(function(){
    $.ajax({
        type:"GET",
        url:url,
        async:true,
        dataType: "json",
           success: function(json) {
              // Parse the response.
              // Do other things.
           },
           error: function(xhr, status, err) {
              // This is where we end up!
            }
    });
  });
});
</script>

Uma solução para este problema é criar um proxy de API do Apigee que chame a API de serviço no back-end. Lembre-se de que o Apigee está entre o cliente (neste caso, um navegador) e a API de back-end (o serviço). Uma vez que o proxy de API é executado no servidor e não num navegador, consegue chamar o serviço com êxito. Em seguida, só tem de anexar cabeçalhos CORS à resposta TargetEndpoint. Desde que o navegador suporte CORS, estes cabeçalhos indicam ao navegador que não há problema em relaxar a respetiva política de mesma origem, o que permite que a chamada da API de origem cruzada seja bem-sucedida.

Depois de criar o proxy com suporte para CORS, pode chamar o URL do proxy da API em vez do serviço de back-end no seu código do lado do cliente. Por exemplo:

<script>
var url = "http://myorg-test.apigee.net/v1/example";
$(document).ready(function(){
  $("button").click(function(){
    $.ajax({
        type:"GET",
        url:url,
        async:true,
        dataType: "json",
           success: function(json) {
              // Parse the response.
              // Do other things.
           },
           error: function(xhr, status, err) {
              // This time, we do not end up here!
            }
    });
  });
});
</script>

Anexar a política CORS ao PreFlow do ProxyEndpoint

Anexar uma política de CORS a um novo proxy de API

Pode adicionar suporte de CORS a um proxy de API anexando uma política Adicionar CORS ao proxy de API das seguintes formas:

  • Quando cria a política selecionando a caixa de verificação Adicionar cabeçalhos CORS na página Segurança do assistente Criar um proxy
  • Adicionando-o mais tarde na caixa de diálogo Adicionar política

Quando adiciona a política de CORS selecionando a caixa de verificação, é adicionada automaticamente uma política denominada Adicionar CORS ao sistema e anexada ao preflow do pedido TargetEndpoint.

A política Adicionar CORS adiciona os cabeçalhos adequados à resposta. Basicamente, os cabeçalhos informam o navegador com que origens vai partilhar os respetivos recursos, que métodos aceita e assim sucessivamente. Pode ler mais acerca destes cabeçalhos CORS na Recomendação W3C de Partilha de Recursos de Origem Cruzada.

Deve modificar a política da seguinte forma:

  • Adicione os cabeçalhos content-type e authorization (obrigatórios para suportar a autenticação básica ou o OAuth2) ao cabeçalho Access-Control-Allow-Headers, conforme mostrado no excerto de código abaixo.
  • Para a autenticação OAuth2, pode ter de tomar medidas para corrigir o comportamento não compatível com a RFC.
<CORS continueOnError="false" enabled="true" name="add-cors">
    <DisplayName>Add CORS</DisplayName>
    <AllowOrigins>{request.header.origin}</AllowOrigins>
    <AllowMethods>GET, PUT, POST, DELETE</AllowMethods>
    <AllowHeaders>origin, x-requested-with, accept, content-type, authorization</AllowHeaders>
    <ExposeHeaders>*</ExposeHeaders>
    <MaxAge>3628800</MaxAge>
    <AllowCredentials>false</AllowCredentials>
    <GeneratePreflightResponse>true</GeneratePreflightResponse>
    <IgnoreUnresolvedVariables>true</IgnoreUnresolvedVariables>
</CORS>

Adicionar cabeçalhos CORS a um proxy existente

Novo editor de proxy

Para adicionar a política CORS a um proxy de API existente:

  1. Se estiver a usar a IU do Apigee na consola do Google Cloud: selecione Desenvolvimento de proxy > Proxies de API.

    Se estiver a usar a IU do Apigee clássica: selecione Develop > API Proxies e, no painel Proxies, selecione o ambiente para o proxy.

  2. Selecione o proxy de API ao qual quer adicionar a política de CORS.
  3. No editor do novo proxy de API, clique no separador Develop.
  4. No painel do lado esquerdo, clique no botão + na linha Políticas.
  5. Na caixa de diálogo Criar política, clique no campo Selecionar tipo de política e desloque a página para baixo até Segurança e selecione CORS.

  6. Introduza os detalhes da política e clique em Criar.

  7. No painel do lado esquerdo, clique em PreFlow em Target Endpoints > default.
  8. Clique no botão + junto a PreFlow no painel Pedido na parte inferior direita do editor visual.
  9. Na caixa de diálogo Adicionar passo de política, selecione a política CORS.
  10. Clique em Adicionar para anexar a política.

Editor de proxy clássico

Para adicionar a política CORS a um proxy de API existente:

  1. Inicie sessão na IU do Apigee.
  2. Selecione Desenvolver > Proxies de API na barra de navegação do lado esquerdo.
  3. Se vir o botão Experimentar agora, clique nele para apresentar a nova vista Desenvolver.

    A vista Desenvolver é apresentada abaixo.

    Desenvolva a vista no editor de proxy

  4. Selecione o proxy de API ao qual quer adicionar a política de CORS.
  5. No editor do novo proxy de API, clique no separador Develop:
  6. No painel de navegação do lado esquerdo, clique em PreFlow em Target Endpoints > default.
  7. Clique no botão +Passo superior, correspondente ao pedido PreFlow. É apresentada uma lista categorizada de todas as políticas que pode criar.
  8. Selecione CORS na categoria Segurança.
  9. Indique um nome, como Add CORS e, de seguida, clique em Adicionar.

Processamento de pedidos de verificação prévia do CORS

A verificação prévia do CORS refere-se ao envio de um pedido a um servidor para verificar se este suporta o CORS. As respostas de verificação prévia típicas incluem as origens a partir das quais o servidor aceita pedidos CORS, uma lista de métodos HTTP suportados para pedidos CORS, cabeçalhos que podem ser usados como parte do pedido de recursos, o tempo máximo durante o qual a resposta de verificação prévia é colocada em cache e outros. Se o serviço não indicar compatibilidade com CORS ou não quiser aceitar pedidos de origem cruzada da origem do cliente, a política de origem cruzada do navegador é aplicada e todos os pedidos de domínio cruzado feitos a partir do cliente para interagir com recursos alojados nesse servidor falham.

Normalmente, os pedidos de verificação prévia da CORS são feitos com o método HTTP OPTIONS. Quando um servidor que suporta CORS recebe um pedido OPTIONS, devolve um conjunto de cabeçalhos CORS ao cliente que indicam o respetivo nível de suporte de CORS. Como resultado desta troca de informações, o cliente sabe o que lhe é permitido pedir ao domínio não de origem.

Para mais informações sobre a pré-validação, consulte a recomendação W3C de partilha de recursos de origem cruzada. Além disso, existem inúmeros blogues e artigos sobre o CORS que pode consultar.

O Apigee não inclui uma solução de verificação prévia de CORS pronta a usar, mas é possível implementá-la, conforme descrito nesta secção. O objetivo é que o proxy avalie um pedido OPTIONS num fluxo condicional. Em seguida, o proxy pode enviar uma resposta adequada de volta ao cliente.

Vejamos um fluxo de exemplo e, em seguida, abordemos as partes que processam o pedido de pré-voo:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<ProxyEndpoint name="default">
    <Description/>
    <Flows>
        <Flow name="OptionsPreFlight">
            <Request>
                <Step>
                    <Name>add-cors</Name>
                </Step>
            </Request>
            <Response/>
        <Condition>request.verb == "OPTIONS" AND request.header.origin != null AND request.header.Access-Control-Request-Method != null</Condition>
        </Flow>
    </Flows>

    <PreFlow name="PreFlow">
        <Request/>
        <Response/>

    </PreFlow>
    <HTTPProxyConnection>
        <BasePath>/v1/cnc</BasePath>
        <VirtualHost>default</VirtualHost>
        <VirtualHost>secure</VirtualHost>
    </HTTPProxyConnection>
    <RouteRule name="NoRoute">
        <Condition>request.verb == "OPTIONS" AND request.header.origin != null AND request.header.Access-Control-Request-Method != null</Condition>
    </RouteRule>
    <RouteRule name="default">
        <TargetEndpoint>default</TargetEndpoint>
   </RouteRule>
   <PostFlow name="PostFlow">
        <Request/>
        <Response/>
    </PostFlow>
</ProxyEndpoint>

As partes principais deste ProxyEndpoint são as seguintes:

  • É criada uma RouteRule para um destino NULL com uma condição para o pedido OPTIONS. Tenha em atenção que não existe nenhum TargetEndpoint especificado. Se o pedido OPTIONS for recebido e os cabeçalhos do pedido Origin e Access-Control-Request-Method não forem nulos, o proxy devolve imediatamente os cabeçalhos CORS numa resposta ao cliente (ignorando o destino "backend" predefinido real). Para ver detalhes sobre as condições de fluxo e a RouteRule, consulte o artigo Condições com variáveis de fluxo.
    <RouteRule name="NoRoute">
        <Condition>request.verb == "OPTIONS" AND request.header.origin != null AND request.header.Access-Control-Request-Method != null</Condition>
    </RouteRule>
  • É criado um fluxo OptionsPreFlight que adiciona uma política de CORS, contendo os cabeçalhos de CORS, ao fluxo se for recebido um pedido OPTIONS e os cabeçalhos de pedido Origin e Access-Control-Request-Method não forem nulos.
     <Flow name="OptionsPreFlight">
                <Request>
                    <Step>
                        <Name>add-cors</Name>
                    </Step>
                </Request>
                <Response/>
            <Condition>request.verb == "OPTIONS" AND request.header.origin != null AND request.header.Access-Control-Request-Method != null</Condition>
     </Flow>