Intercetador MSAL

O MSAL Angular fornece uma classe Interceptor que adquire automaticamente tokens para pedidos enviados que utilizam o cliente Angular http para recursos protegidos conhecidos. Este documento fornece mais informações sobre a configuração e utilização do MsalInterceptor.

Embora recomendemos usar diretamente a MsalInterceptor API em vez da acquireTokenSilent API, por favor note que a utilização MsalInterceptor é opcional. Poderá preferir adquirir tokens explicitamente através das APIs acquireToken em vez disso.

Note que o MsalInterceptor é fornecido para sua comodidade e poderá não se adequar a todos os casos de uso. Encorajamo-lo a escrever o seu próprio interceptor se tiver necessidades específicas que não sejam abordadas pelo MsalInterceptor.

Configuração

Configuração do MsalInterceptor em app.module.ts

O MsalInterceptor pode ser adicionado à sua aplicação como provedor no ficheiro app.module.ts, juntamente com a respetiva configuração. A importação inclui uma instância de MSAL, bem como dois objetos de configuração específicos do Angular. O terceiro argumento é um MsalInterceptorConfiguration objeto, que contém os valores para interactionType, a protectedResourceMap, e um opcional authRequest.

A sua configuração pode parecer a que está abaixo. Consulte o nosso documento de configuração sobre outras formas de configurar o MSAL Angular para a sua aplicação.

import { NgModule } from '@angular/core';
import { HTTP_INTERCEPTORS, HttpClientModule } from "@angular/common/http";
import { AppComponent } from './app.component';
import { MsalModule, MsalRedirectComponent, MsalGuard, MsalInterceptor } from '@azure/msal-angular'; // Import MsalInterceptor
import { InteractionType, PublicClientApplication } from '@azure/msal-browser';

@NgModule({
    declarations: [
        AppComponent,
    ],
    imports: [
        MsalModule.forRoot( new PublicClientApplication({
            // MSAL Configuration
        }), {
            // MSAL Guard Configuration
        }, {
            // MSAL Interceptor Configurations
            interactionType: InteractionType.Redirect,
            protectedResourceMap: new Map([ 
                ['Enter_the_Graph_Endpoint_Here/v1.0/me', ['user.read']]
            ])
        })
    ],
    providers: [
        {
            provide: HTTP_INTERCEPTORS, // Provides as HTTP Interceptor
            useClass: MsalInterceptor,
            multi: true
        },
        MsalGuard
    ],
    bootstrap: [AppComponent, MsalRedirectComponent]
})
export class AppModule { }

Tipo de Interação

Embora o MsalInterceptor tenha sido concebido para obter tokens silenciosamente, se um pedido silencioso falhar, recorrerá à obtenção interativa de tokens. Podem InteractionType ser importados de @azure/msal-browser e definidos para Popup ou Redirect.

{
    interactionType: InteractionType.Redirect,
    protectedResourceMap: new Map([ 
        ['Enter_the_Graph_Endpoint_Here/v1.0/me', ['user.read']]
    ])
}

Mapa de Recursos Protegidos

Os recursos protegidos e os respetivos escopos são fornecidos como a protectedResourceMap na MsalInterceptor configuração.

Os URL que fornece na coleção protectedResourceMap fazem distinção entre maiúsculas e minúsculas. Para cada recurso, adicione os âmbitos pedidos para serem incluídos no token de acesso.

Por exemplo:

  • ["user.read"] para Microsoft Graph
  • ["<Application ID URL>/scope"] para APIs web personalizadas (isto é, api://<Application ID>/access_as_user)

Os escopos podem ser especificados para um recurso das seguintes formas:

  1. Um conjunto de âmbitos que será adicionado a cada pedido HTTP para esse recurso, independentemente do método HTTP utilizado.
{
    interactionType: InteractionType.Redirect,
    protectedResourceMap: new Map<string, Array<string> | null>([
        ["https://graph.microsoft.com/v1.0/me", ["user.read", "profile"]],
        ["https://myapplication.com/user/*", ["customscope.read"]]
    ]),
}
  1. Um array de ProtectedResourceScopes, que associará âmbitos apenas a métodos HTTP específicos.
{
    interactionType: InteractionType.Redirect,
    protectedResourceMap: new Map<string, Array<string|ProtectedResourceScopes> | null>([
        ["https://graph.microsoft.com/v1.0/me", ["user.read"]],
        ["http://myapplication.com", [
            {
                httpMethod: "POST",
                scopes: ["write.scope"]
            }
        ]]
    ])
}

Note-se que os escopos de um recurso podem conter uma combinação de cadeias e ProtectedResourceScopes. No exemplo abaixo, um GET pedido terá os escopos "all.scope" e "read.scope", ao passo que um PUT pedido terá apenas "all.scope".

{
    interactionType: InteractionType.Redirect,
    protectedResourceMap: new Map<string, Array<string|ProtectedResourceScopes> | null>([
        ["http://myapplication.com", [
            "all.scope",
            {
                httpMethod: "GET",
                scopes: ["read.scope"]
            },
            {
                httpMethod: "POST",
                scopes: ["info.scope"]
            }
        ]]
    ])
}
  1. Um valor de âmbito de null, indica que um recurso deve ser desprotegido e não receberá tokens. Recursos não incluídos no protectedResourceMap não estão protegidos por defeito. Especificar um determinado recurso como desprotegido pode ser útil quando algumas rotas de um recurso devem ser protegidas e outras não. Note que a ordem em protectedResourceMap importa, por isso o recurso nulo deve ser colocado antes de quaisquer URLs de base ou curingas semelhantes.
{
    interactionType: InteractionType.Redirect,
    protectedResourceMap: new Map<string, Array<string> | null>([
        ["https://graph.microsoft.com/v1.0/me", ["user.read", "profile"]],
        ["https://myapplication.com/unprotected", null],
        ["https://myapplication.com/unprotected/post", [{ httpMethod: 'POST', scopes: null }]],
        ["https://myapplication.com", ["custom.scope"]]
    ]),
}

Outras coisas a notar relativamente ao protectedResourceMap:

  • Wildcards: protectedResourceMap suporta o uso * para wildcards. Ao usar curingas, se forem encontradas várias entradas coincidentes no protectedResourceMap, será utilizada a primeira correspondência encontrada (com base na ordem do protectedResourceMap).
  • Caminhos relativos: Se existirem caminhos relativos de recursos na sua aplicação, pode ser necessário fornecer o caminho relativo no protectedResourceMap. Isto aplica-se também a questões que possam surgir com o ngx-translate. Tenha em atenção que o caminho relativo na sua protectedResourceMap pode ou não precisar de uma barra à esquerda, dependendo da sua aplicação, e poderá ser necessário testar ambas as opções.

Correspondência exata (strictMatching)

No msal-angular v5, a correspondência de padrões de componentes de URL para entradas protectedResourceMap utiliza, por predefinição, semântica de correspondência estrita. O strictMatching campo em MsalInterceptorConfiguration controla este comportamento.

Importante

Se a sua aplicação define dinamicamente as chaves protectedResourceMap (por exemplo, a partir de ficheiros de ambiente, APP_INITIALIZER ou configuração JSON) e essas chaves forem URLs base sem subcaminhos nem carateres universais, a correspondência exata pode impedir silenciosamente que o cabeçalho Authorization seja anexado. Isto resulta em erros 401 sem qualquer erro em tempo de compilação e sem aviso em cada pedido — apenas um único aviso durante a inicialização, se strictMatching não estiver explicitamente configurado. Consulte Resolução de problemas de correspondência estrita para detalhes.

O que muda na correspondência exata

Comportamento Legado (strictMatching: false) Estrito (padrão na versão 5)
Metapersonagem a escapar . e outros metacaracteres regex não são escapados; atuam como operadores regex Todos os metacaracteres (incluindo .) são tratados como literais
A ancorar O padrão pode coincidir em qualquer parte da corda O padrão deve corresponder à corda completa (^…$)
Carácter universal do anfitrião (*) * corresponde a qualquer sequência de personagens, incluindo . * corresponde a qualquer sequência de caracteres que não inclua . (os curingas ficam dentro de um único rótulo DNS)
Curinga de caminho/pesquisa/hash (*) * corresponde a qualquer sequência de caracteres * corresponde a qualquer sequência de caracteres (inalterada)
? Personagem Transmitido para o regex subjacente Tratado como literal? (separador da cadeia de consulta do URL, não um coringa)

Com correspondência estrita (o padrão da v5):

  • Um padrão como *.contoso.com corresponde, app.contoso.com mas nãoa.b.contoso.com (o coringa não pode abranger separadores de pontos).
  • Um padrão como https://graph.microsoft.com/v1.0/me corresponde apenas a esse URL exato.

Padrões de falha comuns

Os seguintes protectedResourceMap padrões de chave funcionam com a correspondência legada, mas falham silenciosamente com a correspondência estrita:

Padrão de teclas URL da solicitação de saída Resultado com correspondência estrita Corrigir
https://api.example.com https://api.example.com/v1/users Sem correspondência — a chave é resolvida para o caminho /, a requisição tem o caminho /v1/users https://api.example.com/*
https://api.example.com/ https://api.example.com/v1/users Sem correspondência — a barra final faz com que o padrão corresponda exatamente a / https://api.example.com/*
environment.apiConfig.uri (por exemplo, https://api.example.com) https://api.example.com/v1/users Sem correspondência — igual ao anterior `${environment.apiConfig.uri}/*`

Comportamento padrão na v5 (sem necessidade de configuração)

A correspondência estrita está ativada por defeito. Não é necessária configuração adicional:

{
    interactionType: InteractionType.Redirect,
    protectedResourceMap: new Map([
        ["https://*.contoso.com/api", ["contoso.scope"]],
        ["https://graph.microsoft.com/v1.0/me", ["user.read"]]
    ])
    // strictMatching defaults to true in v5
}

Optar por não fazer correspondência de legado

Se os seus padrões dependerem da correspondência menos restritiva da versão 4, pode definir strictMatching: false para manter temporariamente o comportamento legado:

Note

A correspondência antiga (strictMatching: false) é disponibilizada para retrocompatibilidade e poderá ser removida numa futura versão principal. Recomendamos atualizar os seus protectedResourceMap padrões para funcionarem com correspondência exata.

{
    interactionType: InteractionType.Redirect,
    protectedResourceMap: new Map([
        ["https://*.contoso.com/api", ["contoso.scope"]],
        ["https://graph.microsoft.com/v1.0/me", ["user.read"]]
    ]),
    strictMatching: false  // Use legacy matching for backwards compatibility
}

Orientação para configurações orientadas pelo ambiente

Se as suas protectedResourceMap chaves referenciam valores angulares environment (por exemplo, environment.apiConfig.uri), verifique se esses valores são caminhos exatos (por exemplo, https://graph.microsoft.com/v1.0/me) ou URLs base simples (por exemplo, https://api.example.com). Os caminhos exatos funcionam corretamente com correspondência exata e não precisam de tratamento especial:

export function MSALInterceptorConfigFactory(): MsalInterceptorConfiguration {
  const protectedResourceMap = new Map<string, Array<string>>();
  // environment.apiConfig.uri is an exact path (e.g. "https://graph.microsoft.com/v1.0/me")
  // — strict matching works correctly
  protectedResourceMap.set(environment.apiConfig.uri, environment.apiConfig.scopes);

  return {
    interactionType: InteractionType.Redirect,
    protectedResourceMap,
  };
}

Se o valor da variável de ambiente for uma URL de base simples e precisares de fazer corresponder subcaminhos, acrescenta um carácter universal /*:

  // environment.apiConfig.uri is a base URL (e.g. "https://api.example.com")
  // Append /* to match all sub-paths
  protectedResourceMap.set(`${environment.apiConfig.uri}/*`, environment.apiConfig.scopes);

Para configurações verdadeiramente dinâmicas onde a forma da chave não é conhecida em tempo de compilação (por exemplo, APP_INITIALIZER, JSON carregado via fetch, ou platformBrowserDynamic), define strictMatching: false como um padrão temporário seguro. Veja Opções de correção—Opção B para um exemplo de código.

Resolução de problemas de correspondência estrita

Sintomas
  • Os pedidos de API retornam 401 Não autorizado após a atualização para @azure/msal-angular a v5 (ou entre versões menores da v5, como 5.0.x → 5.1.x).
  • O Authorization: Bearer <token> cabeçalho está ausente nos pedidos HTTP enviados.
  • Não são reportados erros em tempo de construção ou de execução — a falha é silenciosa.
  • O problema pode aparecer apenas em certos ambientes (por exemplo, staging/produção) onde a URL base da API difere do desenvolvimento.
Opções de correção

Opção A: Atualizar as chaves para funcionar com correspondência rigorosa (recomendado)

Atualize as suas protectedResourceMap chaves para usar caminhos exatos ou curingas que coincidam sob regras rigorosas de correspondência. Esta abordagem é preferida porque o emparelhamento rigoroso é mais seguro e previsível:

{
    interactionType: InteractionType.Redirect,
    protectedResourceMap: new Map([
        // Exact path — matches only this URL
        ["https://graph.microsoft.com/v1.0/me", ["user.read"]],
        // Wildcard — matches all sub-paths of the API
        ["https://api.example.com/v1/*", ["api.scope"]]
    ])
    // strictMatching defaults to true — no need to set it
}

Opção B: Definir strictMatching: false (alternativa para configurações dinâmicas)

Se as tuas chaves protectedResourceMap forem carregadas dinamicamente em tempo de execução (por exemplo, a partir de APP_INITIALIZER, configuração JSON ou platformBrowserDynamic) e não puderes garantir que contêm caminhos exatos ou carateres universais, define strictMatching: false como valor predefinido temporário seguro:

{
    interactionType: InteractionType.Redirect,
    protectedResourceMap: new Map([
        [config.apiUri, config.apiScopes]
    ]),
    // Dynamic keys may be base URLs without wildcards.
    // Remove once keys are migrated to exact paths or wildcard patterns.
    strictMatching: false
}

Note

A correspondência antiga (strictMatching: false) é fornecida para compatibilidade com versões anteriores e pode ser removida numa futura versão principal.

Aviso de tempo de execução

MsalInterceptor emite um aviso de execução único através do logger MSAL durante a inicialização quando strictMatching não está explicitamente configurado. Se vir este aviso, siga as opções de correção acima.

AuthRequest opcional

Para mais informações sobre o parâmetro opcional authRequest que pode ser definido em MsalInterceptorConfiguration, consulte a nossa documentação multi-inquilino aqui.

Alterações da versão 1 para a versão 2 do msal-angular

Note

O unprotectedResourceMap no MsalAngularConfiguration do MSAL Angular v1 foi descontinuado e já não funciona.

  • protectedResourceMap foi movida para o MsalInterceptorConfiguration objeto, e pode ser passada como Map<string, Array<string|ProtectedResourceScopes>>. MsalAngularConfiguration foi descontinuado e já não funciona.
  • Colocar o domínio raiz no protectedResourceMap para proteger todas as rotas já não é suportado. Por favor, use a correspondência wildcard em vez disso.

Para mais informações sobre como configurar os telescópios, consulte as nossas Perguntas Frequentes.