Compartilhar via


Proteger APIs sem servidor com o Gerenciamento de API do Azure e o Azure AD B2C para o consumo de um SPA

APLICA-SE A: todas as camadas do Gerenciamento de API

Este cenário mostra como configurar sua instância de Gerenciamento de API do Azure para proteger uma API. Usaremos o fluxo Azure AD B2C SPA (Código de Autenticação + PKCE) para adquirir um token, junto com o Gerenciamento de API para proteger um back-end Azure Functions usando o EasyAuth.

Para obter uma visão geral conceitual da autorização da API, consulte Autenticação e autorização no Gerenciamento de API.

Objetivos

Veremos como o Gerenciamento de API pode ser usado em um cenário simplificado com Azure Functions e Azure AD B2C. Você criará um aplicativo JavaScript (JS) chamando uma API, que conecta os usuários com Azure AD B2C. Em seguida, usará o gerenciamento de API Validate-JWT, CORS e o limite de taxa por recursos de política de chave para proteger a API de back-end.

Para uma defesa profunda, usamos EasyAuth para validar o token novamente dentro da API de back-end e garantir que o gerenciamento de API seja o único serviço que pode chamar o back-end Azure Functions.

O que você aprenderá

  • Configuração de um Aplicativo de Página Única e API de back-end no Azure Active Directory B2C
  • Criação de uma API de back-end Azure Functions
  • Importar uma API do Azure Functions para o Gerenciamento de API do Azure
  • Protegendo a API no Gerenciamento de API do Azure
  • Chamando os Pontos de Extremidade de Autorização do Azure Active Directory B2C por meio das Bibliotecas da Plataforma Microsoft Identity (MSAL.js)
  • Armazenando um Aplicativo de Página Única de HTML / Vanilla JS e servindo-o de um Ponto de Extremidade de Armazenamento de Blobs do Azure

Pré-requisitos

Para seguir as etapas deste artigo, você precisa ter:

  • Uma Conta de Armazenamento do Azure (StorageV2) Uso Geral V2 para hospedar o aplicativo de Página Única do front-end JS.
  • Uma instância de Gerenciamento de API do Azure (qualquer camada funcionará, incluindo o “Consumo”, mas determinados recursos aplicáveis ao cenário completo não estão disponíveis nessa camada (limite de taxa por chave e IP Virtual dedicado), essas restrições são indicadas abaixo no artigo onde é apropriado).
  • Um Aplicativo de Funções do Azure vazio (executando o tempo de execução do V 3.1 .NET Core, em um Plano de Consumo) para hospedar a API chamada
  • Um locatário Azure AD B2C, vinculado a uma assinatura.

Embora na prática seriam usados recursos na mesma região em cargas de trabalho de produção, neste artigo de instruções, a região de implantação não é importante.

Visão geral

Aqui está uma ilustração dos componentes em uso e o fluxo entre eles quando esse processo for concluído. Componentes em uso e fluxo

A seguir é apresentada uma visão geral das etapas:

  1. Criar a chamada de Azure AD B2C (front-end, Gerenciamento de API) e Aplicativos de API com escopos e conceder Acesso à API

  2. Criar as políticas de inscrição e entrada para permitir que os usuários entrem com o Azure AD B2C

  3. Configurar o Gerenciamento de API com as novas IDs de cliente Azure AD B2C e chaves para habilitar a autorização de usuário OAuth2 no Console do Desenvolvedor

  4. Criar a API de Função

  5. Configure a API de Função para habilitar o EasyAuth com as novas e as chaves de ID de cliente Azure AD B2C e bloquear para APIM VIP

  6. Compilar a Definição de API no Gerenciamento de API

  7. Configurar o Oauth2 para a configuração da API de Gerenciamento de API

  8. Configurar a política CORS e adicionar a política validate-jwt para validar o token OAuth para cada solicitação de entrada

  9. Compilar o aplicativo de chamada para consumir a API

  10. Carregar a Amostra de SPA do JS

  11. Configurar o Aplicativo de Cliente JS de Amostra com o novo Azure AD B2C ID do cliente e as chaves

  12. Testar o Aplicativo Cliente

    Dica

    Vamos capturar algumas informações e chaves à medida que examinamos este documento. Talvez seja útil ter um editor de texto aberto para armazenar os seguintes itens de configuração temporariamente.

    ID DO CLIENTE DE BACK-END B2C: CHAVE SECRETA DO CLIENTE DE BACK-END B2C: URI DO ESCOPO DA API DE BACK-END B2C: ID DO CLIENTE DE FRONT-END B2C: URI DO PONTO DE EXTREMIDADE DO FLUXO DE USUÁRIO B2C: PONTO DE EXTREMIDADE OPENID CONHECIDO B2C: NOME DA POLÍTICA B2C: Frontendapp_signupandsignin URL DA FUNÇÃO: URL DE BASE DA API DE APIM: URL DO PONTO DE EXTREMIDADE PRIMÁRIO DO ARMAZENAMENTO:

Configurar o aplicativo de back-end

Abra a folha Azure AD B2C no portal e execute as etapas a seguir.

  1. Selecione a guia Registros do Aplicativo

  2. Clique no botão 'Novo Registro'.

  3. Escolha 'Web' na caixa de seleção Redirecionar URI.

  4. Agora, defina o Nome de Exibição, escolha algo exclusivo e relevante para o serviço que está sendo criado. Neste exemplo, usaremos o nome “Aplicativo Back-end”.

  5. Use espaços reservados para as URLs de resposta, como ' https://jwt.ms ' (um site de decodificação de token de propriedade da Microsoft). Atualizaremos essas URLs mais tarde.

  6. Verifique se você selecionou a opção "Contas em qualquer provedor de identidade ou diretório organizacional (para autenticar usuários com fluxos de usuário)"

  7. Para este exemplo, desmarque a caixa "Conceder consentimento de administrador", pois não precisaremos de permissões offline_access hoje.

  8. Clique em "Registrar".

  9. Registre a ID do cliente do Aplicativo de Back-end para uso posterior (mostrado em ' ID do Aplicativo (cliente) ').

  10. Selecione a guia Certificados e Segredos (em gerenciar) e clique em 'Novo Segredo de Cliente' para gerar uma chave de autenticação (aceite as configurações padrão e clique em 'Adicionar').

  11. Ao clicar em 'Adicionar', copie a chave (em 'valor') em algum lugar seguro para uso posterior como 'Segredo do cliente de Back-end '. Observe que essa caixa de diálogo é a única chance para copiar essa chave.

  12. Agora, selecione a guia Expor uma API (em Gerenciar).

  13. Você será solicitado a definir o URI AppID, selecionar e registrar o valor padrão.

  14. Criar e nomear o escopo "Olá" para sua API de Função. É possível usar a frase 'Olá' para todas as opções que podem ser inseridas, gravando o URI de valor completo do escopo preenchido e, em seguida, clicando em 'Adicionar escopo'.

  15. Retorne à raiz da folha Azure AD B2C selecionando a trilha 'Azure AD B2C' na parte superior esquerda do portal.

    Observação

    Os escopos de Azure AD B2C são efetivamente permissões em sua API para que outros aplicativos possam solicitar acesso por meio da folha de acesso à API de seus aplicativos. Efetivamente, acabaram de ser criadas permissões de aplicativo para sua API chamada.

Configurar o aplicativo front-end

  1. Selecione a guia Registros do Aplicativo
  2. Clique no botão 'Novo Registro'.
  3. Escolha "Aplicativo de Página Única (SPA)" na caixa de seleção Redirecionar URI.
  4. Agora, defina o nome de exibição e o URI de AppID. Aqui, escolha algo exclusivo e relevante para o aplicativo front-end que usará esse registro de aplicativo do Azure Active Directory B2C. Neste exemplo, é possível usar "Aplicativo de front-end"
  5. De acordo com o primeiro registro do aplicativo, deixe a seleção de tipos de conta com suporte como padrão (autenticando usuários com fluxos de usuário)
  6. Use espaços reservados para as URLs de resposta, como ' https://jwt.ms ' (um site de decodificação de token de propriedade da Microsoft). Atualizaremos essas URLs mais tarde.
  7. Deixe a caixa de conceder consentimento ao administrador marcada
  8. Clique em "Registrar".
  9. Registre a ID do Cliente do Aplicativo Front-end para uso posterior (mostrado em 'ID do Aplicativo (cliente)').
  10. Alterne para a guia Permissões de API.
  11. Conceda acesso ao aplicativo de back-end clicando em 'adicionar uma permissão'; depois em 'Minhas APIs'; selecione 'Aplicativo de Back-end'; selecione 'Permissões'; selecione o escopo criado na seção anterior e clique em 'Adicionar permissões'
  12. Clique em 'Conceder consentimento de administrador para {tenant}' e clique em 'Sim' na caixa de diálogo pop-up. Esse pop-up consentiu o "Aplicativo Front-end" para usar a permissão "hello" definida no "Aplicativo de Back-end" criado anteriormente.
  13. Todas as Permissões agora devem ser mostradas para o aplicativo como uma marca em verde na coluna status

Criar um fluxo de usuário de “Inscrição e Logon”

  1. Retorne à raiz da folha B2C selecionando a trilha Azure AD B2C.

  2. Alterne para a guia 'Fluxos dos Usuários' (em Políticas).

  3. Clique em "Novo fluxo de usuário"

  4. Escolha o tipo de fluxo de usuário de "Inscrição e Logon", selecione "Recomendado" e, em seguida, clique em "Criar"

  5. Dê um nome à política e registre-a para mais tarde. Para este exemplo, é possível usar "Frontendapp_signupandsignin". Observe que isso será prefixado com "B2C_1_" para tornar "B2C_1_Frontendapp_signupandsignin"

  6. Em "provedores de identidade" e "Contas locais", marque "Inscrição de email" (ou "Inscrição de ID de usuário", dependendo da configuração de seu locatário B2C) e clique em OK. Essa configuração ocorre devido ao registro de contas B2C locais, não ao adiamento para outro provedor de identidade (como um provedor de identidade social) para usar a conta de mídia social existente de um usuário.

  7. Deixe as configurações de acesso condicional e MFA em seus padrões.

  8. Em 'Atributos e declarações de usuário', clique em 'Mostrar mais... '. Em seguida, escolha as opções de declaração que deseja que os usuários insiram e que retornaram no token. Verifique pelo menos “Nome de exibição” e “Endereço de email” para coletar, com “Nome de exibição” e “Endereços de email” para retornar (preste atenção ao fato de que você está coletando endereço de email, no singular, e pedindo para retornar endereços de email, no plural). Em seguida, clique em “OK” e depois em “Criar”.

  9. Clique no fluxo de usuário criado na lista e clique no botão 'Executar fluxo de usuário'.

  10. Essa ação abrirá a folha executar fluxo de usuário, selecionará o aplicativo front-end, copiará o ponto de extremidade do fluxo do usuário e o salvará para mais tarde.

  11. Copie e armazene o link na parte superior, registrando como o "ponto de extremidade de configuração do OpenID conhecido" para uso posterior.

    Observação

    As políticas B2C permitem expor os pontos de extremidade de logon Azure AD B2C para poder capturar diferentes componentes de dados e conectar usuários de maneiras diferentes.

    Nesse caso, um fluxo de inscrição ou logon foi configurado (política). Isso também expôs um ponto de extremidade de configuração bem conhecido, em ambos os casos em que nossa política criada foi identificada na URL pelo parâmetro de cadeia de caracteres de consulta "p=".

    Quando isso for feito, agora você terá uma plataforma de identidade funcional Da Empresa para o Consumidor que conectará os usuários em vários aplicativos.

Criar a API de Função

  1. Volte para o seu locatário do Microsoft Entra padrão no portal do Azure para que possamos configurar itens em sua assinatura novamente.

  2. Vá para a folha aplicativos de funções do portal do Azure, abra o aplicativo de funções vazio e clique em 'funções' e clique em 'Adicionar'.

  3. No submenu que aparece, escolha 'Desenvolver no portal' em 'selecionar um modelo' e escolha 'gatilho HTTP'. Em detalhes de Modelo nomeie-o como 'Olá' com o nível de autorização 'Função' e selecione Adicionar.

  4. Alterne para a folha Código + Teste e copie e cole o código de exemplo abaixo sobre o código existente que aparece.

  5. Selecione Salvar.

    
    using System.Net;
    using Microsoft.AspNetCore.Mvc;
    using Microsoft.Extensions.Primitives;
    
    public static async Task<IActionResult> Run(HttpRequest req, ILogger log)
    {
       log.LogInformation("C# HTTP trigger function processed a request.");
    
       return (ActionResult)new OkObjectResult($"Hello World, time and date are {DateTime.Now.ToString()}");
    }
    
    

    Dica

    O código da função script C# que você acabou de colar apenas registra uma linha nos logs de funções e retorna o texto "Olá, Mundo" com alguns dados dinâmicos (data e hora).

  6. Selecione "Integração" na folha à esquerda e clique no link http (req) dentro da caixa "Gatilho".

  7. Na lista suspensa 'Métodos HTTP selecionados' desmarque o método HTTP POST, deixando apenas OBTER selecionado e, em seguida, clique em salvar.

  8. Volte para a guia Código + Teste, clique em "Obter URL da Função". Em seguida, copie a URL que aparece e salve-a para mais tarde.

    Observação

    As associações recentemente criadas apenas informam funções para responder a solicitações HTTP GET anônimas para a URL que acabou de ser copiada ( https://yourfunctionappname.azurewebsites.net/api/hello?code=secretkey ). Agora temos uma API https sem servidor escalonável, que é capaz de retornar uma carga muito simples.

    Agora é possível testar a chamada dessa API de um navegador da Web usando sua versão da URL acima que acabou de ser copiada e salva. É possível remover também a parte dos parâmetros da cadeia de caracteres de consulta "?code=secretkey" da URL e testar novamente para provar que Azure Functions retornará um erro 401.

Configurar e proteger a API de função

  1. Duas áreas extras no aplicativo de funções precisam ser configuradas (Restrições de Rede e Autorização).

  2. Em primeiro lugar, vamos configurar a autenticação/autorização. Portanto, navegue de volta para a folha raiz do aplicativo de funções através da trilha.

  3. Em seguida, em “Configurações”, clique em “Autenticação”.

  4. Clique em “Adicionar provedor de identidade”.

  5. Selecione “Microsoft” na lista suspensa de Provedores de Identidade.

  6. Em Registro de Aplicativo, selecione “Fornecer os detalhes de um registro de aplicativo existente”.

  7. Cole a ID do cliente do aplicativo de back-end (do Azure AD B2C) na caixa “ID do aplicativo (cliente)” (essa configuração foi realizada anteriormente).

  8. Cole o ponto de extremidade de configuração do Open-ID conhecido da política de inscrição e logon na caixa URL do Emissor (essa configuração foi registrada anteriormente).

  9. Cole o segredo do cliente do aplicativo de back-end na caixa apropriada (essa configuração foi realizada anteriormente).

  10. Para “Solicitações não autenticadas”, selecione “HTTP 401 Não autorizado: recomendado para APIs”.

  11. Mantenha Armazenamento de Token habilitado (padrão).

  12. Clique em 'Salvar' (na parte superior esquerda da folha).

    Importante

    Agora, sua API de Função será implantada e deverá lançar 401 respostas se o JWT correto não for fornecido como uma Autorização: cabeçalho do portador, e deverá retornar dados quando uma solicitação válida for apresentada. Foi adicionada segurança adicional de defesa aprofundada no EasyAuth ao configurar a opção 'Fazer logon com o Microsoft Entra ID' para lidar com solicitações não autenticadas.

    Ainda não temos nenhuma segurança IP aplicada, se você tiver uma chave válida e um token OAuth2, qualquer pessoa poderá chamá-la de qualquer lugar. Idealmente, queremos forçar todas as solicitações a surgirem por meio do Gerenciamento de API.

    Se você estiver usando as camadas Consumo de Gerenciamento de API, Basic v2 e Standard v2, não haverá um IP virtual de Gerenciamento de API do Azure dedicado para permitir lista com as restrições de acesso das funções. Nas camadas clássicas (dedicadas) do Gerenciamento de API do Azure, o VIP é um locatário único e tem a duração do tempo de vida do recurso. Para as camadas executadas na infraestrutura compartilhada, você pode bloquear suas chamadas à API por meio da chave de função de segredo compartilhado na parte do URI copiado acima. Além disso, para essas camadas - as etapas 12-17 abaixo não se aplicam.

  13. Feche a folha "Autenticação" do portal do Serviço de Aplicativo/Functions.

  14. Abra a folha Gerenciamento de API do portale, em seguida, abra sua instância.

  15. Registre o VIP Privado mostrado na guia visão geral.

  16. Retorne à folha Azure Functions do portal e abra sua instância novamente.

  17. Selecione 'Rede' e, em seguida, selecione 'Configurar restrições de acesso'

  18. Clique em 'Adicionar regra' e insira o VIP copiado na etapa 3 acima no formato XX. XX. XX. XX/32.

  19. Caso queira continuar a interagir com o portal de funções e executar as etapas opcionais abaixo, deverá adicionar seu próprio endereço IP público ou intervalo CIDR aqui.

  20. Quando houver uma entrada de permissão na lista, o Azure adicionará uma regra de negação implícita para bloquear todos os outros endereços.

Será necessário adicionar blocos de endereços formatados por CIDR ao painel restrições de IP. Quando for preciso adicionar um único endereço, como o VIP de gerenciamento de API, será necessário adicioná-lo no formato xx.xx.xx.xx/32.

Observação

Agora, sua API de função não deve ser “chamável” de qualquer lugar além do Gerenciamento de API ou seu endereço.

  1. Abra a folha Gerenciamento de APIe, em seguida, abra sua instância.

  2. Selecione a Folha APIs (em APIs).

  3. No painel 'Adicionar uma Nova API', escolha 'Aplicativo de Função ' e, em seguida, selecione 'Completo' na parte superior do pop-up.

  4. Clique em Procurar, escolha o aplicativo de função no qual está hospedando a API e clique em selecionar. Clique em selecionar novamente.

  5. Dê ao API um nome e uma descrição para o uso interno do Gerenciamento de API e adicione-o ao Produto ' ilimitado '.

  6. Copie e registre a 'URL base' da API e clique em 'criar'.

  7. Clique na guia “Configurações” e, em assinatura, desative a caixa de seleção “Assinatura necessária”, pois usaremos o token JWT OAuth nesse caso para obter o limite de taxa. Observe que, caso esteja usando a camada de consumo, isso ainda seria necessário em um ambiente de produção.

    Dica

    Se estiver usando a camada de consumo de APIM, o produto ilimitado não estará disponível pronto para uso. Em vez disso, navegue até "Produtos" em "APIs" e clique em "Adicionar". Digite "Ilimitado" como o nome do produto e a descrição e selecione a API que você acabou de adicionar do texto explicativo de APIs "+" na parte inferior esquerda da tela. Selecione a caixa “publicado”. Deixe o restante no formato padrão. Por fim, pressione o botão "criar". Com isso, foi criado o produto "ilimitado" e atribuído à sua API. É possível personalizar o novo produto mais tarde.

Configurar e capturar as configurações corretas do ponto de extremidade de armazenamento

  1. Abra a folha contas de armazenamento na portal do Azure

  2. Selecione a conta que criou e selecione a folha "site estático" na seção Configurações (caso não veja uma opção "site estático", verifique se foi criada uma conta V2).

  3. Defina o recurso de hospedagem da Web estática como 'habilitado' e defina o nome do documento de índice como 'index.html' e clique em 'salvar'.

  4. Anote o conteúdo do 'Ponto de Extremidade Primário' para mais tarde, pois esse local é onde o site de front-end será hospedado.

    Dica

    É possível usar o armazenamento de Blobs do Azure + a regravação de CDN ou Azure App Service para hospedar o recurso de Hospedagem de Site Estático do SPA, mas o armazenamento de Blobs nos oferece um contêiner padrão para fornecer conteúdo da Web estático/HTML/js/CSS do armazenamento do Azure e inferirá uma página padrão para nós sem nenhum trabalho.

Configurar as políticas CORS e Validate-JWT

As seções a seguir devem ser seguidas, independentemente da camada APIM que está sendo usada. A URL da conta de armazenamento é da conta de armazenamento que terá disponibilizado nos pré-requisitos na parte superior deste artigo.

  1. Alterne para a folha gerenciamento de API do portal e abra sua instância.

  2. Selecione APIs e, em seguida, selecione "Todas as APIs".

  3. Em "Processamento de entrada", clique no botão de exibição de código "</>" para mostrar o editor de política.

  4. Edite a seção de entrada e cole o XML abaixo para que ele seja lido da seguinte maneira.

  5. Substitua os seguintes parâmetros na Política

  6. {PrimaryStorageEndpoint} (O 'Ponto de Extremidade de Armazenamento Primário' copiado na seção anterior), {b2cpolicy-well-known-OpenID} (o 'Ponto de Extremidade de Configuração do OpenID conhecido ' que você copiou anteriormente) e {backend-API-Application-Client-ID} (a ID do Aplicativo/Cliente B2C para a API de Back-end) com os valores corretos salvos anteriormente.

  7. Se você estiver usando a camada de Consumo do Gerenciamento de API, deverá remover a política de limite de taxa por chave, pois essa política não está disponível ao usar a camada de Consumo do Gerenciamento de API do Azure.

    <inbound>
       <cors allow-credentials="true">
             <allowed-origins>
                 <origin>{PrimaryStorageEndpoint}</origin>
             </allowed-origins>
             <allowed-methods preflight-result-max-age="120">
                 <method>GET</method>
             </allowed-methods>
             <allowed-headers>
                 <header>*</header>
             </allowed-headers>
             <expose-headers>
                 <header>*</header>
             </expose-headers>
         </cors>
       <validate-jwt header-name="Authorization" failed-validation-httpcode="401" failed-validation-error-message="Unauthorized. Access token is missing or invalid." require-expiration-time="true" require-signed-tokens="true" clock-skew="300">
          <openid-config url="{b2cpolicy-well-known-openid}" />
          <required-claims>
             <claim name="aud">
                <value>{backend-api-application-client-id}</value>
             </claim>
          </required-claims>
       </validate-jwt>
       <rate-limit-by-key calls="300" renewal-period="120" counter-key="@(context.Request.IpAddress)" />
       <rate-limit-by-key calls="15" renewal-period="60" counter-key="@(context.Request.Headers.GetValueOrDefault("Authorization","").AsJwt()?.Subject)" />
    </inbound>
    

    Observação

    Agora, o Gerenciamento de API do Azure é capaz de responder a solicitações de origem cruzada de aplicativos SPA JavaScript e executa a limitação, a limitação de taxa e a validação prévia do token de autenticação JWT sendo transmitido ANTES de encaminhar a solicitação para a API de Função.

    Parabéns, agora você tem Azure AD B2C, Gerenciamento de API e Azure Functions trabalhando juntos para publicar, proteger e consumir uma API!

    Dica

    Se estiver usando a camada de consumo do Gerenciamento de API, em vez da limitação de taxa pelo assunto de JWT ou endereço IP de entrada (a política Limitar taxa de chamada por chave não tem suporte atualmente para a camada de “Consumo”), é possível Limitar por cota de taxa de chamada aqui. Como este exemplo é um aplicativo de página única JavaScript, usamos a chave de gerenciamento de API somente para chamadas de cobrança e limitação de taxa. A autorização e a autenticação reais são manipuladas pelo Azure AD B2C e são encapsuladas no JWT, que é validado duas vezes, uma vez por gerenciamento de API e, em seguida, pelo Azure Function de back-end.

Carregar o exemplo de SPA do JavaScript no armazenamento estático

  1. Ainda na folha da conta de armazenamento, selecione a folha ' contêineres ' na seção serviço Blob e clique no contêiner $web que aparece no painel à direita.

  2. Salve o código abaixo em um arquivo localmente em seu computador como index.html e, em seguida, carregue o arquivo index.html para o contêiner $web.

     <!doctype html>
     <html lang="en">
     <head>
          <meta charset="utf-8">
          <meta http-equiv="X-UA-Compatible" content="IE=edge">
          <meta name="viewport" content="width=device-width, initial-scale=1">
          <link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.0-beta2/dist/css/bootstrap.min.css" rel="stylesheet" integrity="sha384-BmbxuPwQa2lc/FVzBcNJ7UAyJxM6wuqIj61tLrc4wSX0szH/Ev+nYRRuWlolflfl" crossorigin="anonymous">
          <script type="text/javascript" src="https://alcdn.msauth.net/browser/2.11.1/js/msal-browser.min.js"></script>
     </head>
     <body>
          <div class="container-fluid">
              <div class="row">
                  <div class="col-md-12">
                     <nav class="navbar navbar-expand-lg navbar-dark bg-dark">
                         <div class="container-fluid">
                             <a class="navbar-brand" href="#">Azure Active Directory B2C with Azure API Management</a>
                             <div class="navbar-nav">
                                 <button class="btn btn-success" id="signinbtn"  onClick="login()">Sign In</a>
                             </div>
                         </div>
                     </nav>
                  </div>
              </div>
              <div class="row">
                  <div class="col-md-12">
                      <div class="card" >
                         <div id="cardheader" class="card-header">
                             <div class="card-text"id="message">Please sign in to continue</div>
                         </div>
                         <div class="card-body">
                             <button class="btn btn-warning" id="callapibtn" onClick="getAPIData()">Call API</a>
                             <div id="progress" class="spinner-border" role="status">
                                 <span class="visually-hidden">Loading...</span>
                             </div>
                         </div>
                      </div>
                  </div>
              </div>
          </div>
          <script lang="javascript">
                 // Just change the values in this config object ONLY.
                 var config = {
                     msal: {
                         auth: {
                             clientId: "{CLIENTID}", // This is the client ID of your FRONTEND application that you registered with the SPA type in Azure Active Directory B2C
                             authority:  "{YOURAUTHORITYB2C}", // Formatted as https://{b2ctenantname}.b2clogin.com/tfp/{b2ctenantguid or full tenant name including onmicrosoft.com}/{signuporinpolicyname}
                             redirectUri: "{StoragePrimaryEndpoint}", // The storage hosting address of the SPA, a web-enabled v2 storage account - recorded earlier as the Primary Endpoint.
                             knownAuthorities: ["{B2CTENANTDOMAIN}"] // {b2ctenantname}.b2clogin.com
                         },
                         cache: {
                             cacheLocation: "sessionStorage",
                             storeAuthStateInCookie: false
                         }
                     },
                     api: {
                         scopes: ["{BACKENDAPISCOPE}"], // The scope that we request for the API from B2C, this should be the backend API scope, with the full URI.
                         backend: "{APIBASEURL}/hello" // The location that we'll call for the backend api, this should be hosted in API Management, suffixed with the name of the API operation (in the sample this is '/hello').
                     }
                 }
                 document.getElementById("callapibtn").hidden = true;
                 document.getElementById("progress").hidden = true;
                 const myMSALObj = new msal.PublicClientApplication(config.msal);
                 myMSALObj.handleRedirectPromise().then((tokenResponse) => {
                     if(tokenResponse !== null){
                         console.log(tokenResponse.account);
                         document.getElementById("message").innerHTML = "Welcome, " + tokenResponse.account.name;
                         document.getElementById("signinbtn").hidden = true;
                         document.getElementById("callapibtn").hidden = false;
                     }}).catch((error) => {console.log("Error Signing in:" + error);
                 });
                 function login() {
                     try {
                         myMSALObj.loginRedirect({scopes: config.api.scopes});
                     } catch (err) {console.log(err);}
                 }
                 function getAPIData() {
                     document.getElementById("progress").hidden = false;
                     document.getElementById("message").innerHTML = "Calling backend ... "
                     document.getElementById("cardheader").classList.remove('bg-success','bg-warning','bg-danger');
                     myMSALObj.acquireTokenSilent({scopes: config.api.scopes, account: getAccount()}).then(tokenResponse => {
                         const headers = new Headers();
                         headers.append("Authorization", `Bearer ${tokenResponse.accessToken}`);
                         fetch(config.api.backend, {method: "GET", headers: headers})
                             .then(async (response)  => {
                                 if (!response.ok)
                                 {
                                     document.getElementById("message").innerHTML = "Error: " + response.status + " " + JSON.parse(await response.text()).message;
                                     document.getElementById("cardheader").classList.add('bg-warning');
                                 }
                                 else
                                 {
                                     document.getElementById("cardheader").classList.add('bg-success');
                                     document.getElementById("message").innerHTML = await response.text();
                                 }
                                 }).catch(async (error) => {
                                     document.getElementById("cardheader").classList.add('bg-danger');
                                     document.getElementById("message").innerHTML = "Error: " + error;
                                 });
                     }).catch(error => {console.log("Error Acquiring Token Silently: " + error);
                         return myMSALObj.acquireTokenRedirect({scopes: config.api.scopes, forceRefresh: false})
                     });
                     document.getElementById("progress").hidden = true;
              }
             function getAccount() {
                 var accounts = myMSALObj.getAllAccounts();
                 if (!accounts || accounts.length === 0) {
                     return null;
                 } else {
                     return accounts[0];
                 }
             }
         </script>
      </body>
     </html>
    
  3. Navegue até o ponto de extremidade primário do site estático armazenado anteriormente na última seção.

    Observação

    Parabéns, você acabou de implantar um aplicativo de página única JavaScript na Hospedagem de conteúdo estático do armazenamento do Azure. Como ainda não configuramos o aplicativo JS com seus Azure AD B2C detalhes – a página ainda não funcionará se for aberta.

Configurar o JavaScript SPA para Azure AD B2C

  1. Agora sabemos onde tudo está: podemos configurar o SPA com o endereço apropriado da API de gerenciamento de API e as IDs de aplicativo/cliente Azure AD B2C corretas.
  2. Voltar para a folha armazenamento portal do Azure
  3. Selecione ' contêineres ' (em ' configurações ')
  4. Selecione o contêiner '$web' na lista
  5. Selecione o blob index.html na lista
  6. Clique em Editar
  7. Atualize os valores de autenticação na seção de configuração MSAL para corresponder ao seu aplicativo de front-end registrado no B2C anteriormente. Use os comentários de código para obter dicas sobre como os valores de configuração devem ser examinados. O valor authority deve estar no formato:- https://{b2ctenantname}. b2clogin. com/TFP/{b2ctenantname}. onmicrosoft. com}/{signupandsigninpolicyname}, se você tiver usado nossos nomes de exemplo e seu locatário B2C for chamado de "contoso", então você esperaria que a autoridade fosse " https://contoso.b2clogin.com/tfp/contoso.onmicrosoft.com/Frontendapp_signupandsignin ".
  8. Defina os valores da API para corresponder ao seu endereço de back-end (a URL base da API registrada anteriormente e os valores ' b2cScopes ' foram registrados anteriormente para o aplicativo de back-end).
  9. Clique em Salvar

Definir os URIs de redirecionamento para o aplicativo de front-end Azure AD B2C

  1. Abra a folha Azure AD B2C e navegue até o registro do aplicativo para o Aplicativo de Frontend do JavaScript.

  2. Clique em 'Redirecionar URIs' e exclua o espaço reservado ' https://jwt.ms ' que inserimos anteriormente.

  3. Adicione um novo URI para o ponto de extremidade primário (armazenamento) (menos a barra à direita).

    Observação

    Essa configuração fará com que um cliente do aplicativo de front-end receba um token de acesso com declarações apropriadas de Azure AD B2C. O SPA poderá adicionar isso como um token de portador no cabeçalho HTTPS na chamada para a API de back-end.

    O gerenciamento de API validará previamente o token, as chamadas de limite de taxa para o ponto de extremidade pelo assunto do JWT emitido pela ID do Azure (o usuário) e pelo endereço IP do chamador (dependendo da camada de serviço do gerenciamento de API, consulte a observação acima), antes de passar pela solicitação para a API de recebimento da Azure Function, adicionando a chave de segurança de funções. O SPA renderizará a resposta no navegador.

    Parabéns, você configurou Azure AD B2C, Gerenciamento de API do Azure, Azure Functions, Autorização de Serviço de Aplicativo do Azure para trabalhar em perfeita harmonia!

Agora temos um aplicativo simples com uma API simples e segura. Vamos testá-lo.

Testar o aplicativo cliente

  1. Abra a URL do aplicativo de exemplo que foi anotada na conta de armazenamento criada anteriormente.
  2. Clique em "Entrar" no canto superior direito para ver seu perfil de inscrição ou logon do Azure AD B2C.
  3. O aplicativo deve receber você pelo seu nome do perfil B2C.
  4. Agora, clique em "Chamar API" e a página deverá ser atualizada com os valores enviados de volta de sua API protegida.
  5. Se clicar repetidamente no botão Chamar API e estiver executando na camada de desenvolvedor ou acima do Gerenciamento de API, sua solução começará a classificar o limite da API e esse recurso deverá ser relatado no aplicativo com uma mensagem apropriada.

E pronto!

As etapas acima podem ser adaptadas e editadas para permitir muitos usos diferentes de Azure AD B2C com o Gerenciamento de API.

Próximas etapas