Interceptor de MSAL

MSAL Angular proporciona una clase Interceptor que adquiere automáticamente tokens para las solicitudes salientes que utilizan el cliente http de Angular para recursos protegidos conocidos. En este documento se proporciona más información sobre la configuración y el uso de MsalInterceptor.

Aunque recomendamos usar MsalInterceptor en lugar de la API acquireTokenSilent directamente, ten en cuenta que usar MsalInterceptor es opcional. Es posible que quiera adquirir tokens explícitamente mediante las API acquireToken en su lugar.

Tenga en cuenta que MsalInterceptor se proporciona para su comodidad y puede no ajustarse a todos los casos de uso. Le invitamos a escribir su propio interceptor si tiene necesidades específicas que no son tratadas por MsalInterceptor.

Configuración

Configurar el MsalInterceptor en el app.module.ts

El MsalInterceptor se puede añadir a su aplicación como proveedor en app.module.ts, junto con su configuración. La importación toma una instancia de MSAL, así como dos objetos de configuración específicos de Angular. El tercer argumento es un objeto MsalInterceptorConfiguration, que contiene los valores para interactionType, un protectedResourceMap y un authRequest opcional.

La configuración puede ser similar a la siguiente. Consulte nuestro documento de configuración sobre otras formas de configurar MSAL Angular para la aplicación.

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 interacción

MsalInterceptor Aunque está diseñado para adquirir tokens de forma silenciosa, en caso de que se produzca un error en una solicitud silenciosa, volverá a adquirir tokens de forma interactiva. InteractionType se puede importar desde @azure/msal-browser y establecer en Popup o Redirect.

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

Mapa de recursos protegido

Los recursos protegidos y los alcances correspondientes se proporcionan como un protectedResourceMap en la configuración MsalInterceptor.

Las direcciones URL que proporciona en la colección protectedResourceMap distinguen mayúsculas de minúsculas. Para cada recurso, agregue los ámbitos cuya devolución se solicita en el token de acceso.

Por ejemplo:

  • ["user.read"] para Microsoft Graph
  • ["<Application ID URL>/scope"] para las API web personalizadas (es decir, api://<Application ID>/access_as_user)

Los ámbitos se pueden especificar para un recurso de las maneras siguientes:

  1. Matriz de ámbitos, que se agregará a cada solicitud HTTP a ese recurso, independientemente del método HTTP.
{
    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. Matriz de ProtectedResourceScopes, que asociará ámbitos solo para 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"]
            }
        ]]
    ])
}

Tenga en cuenta que los ámbitos de un recurso pueden contener una combinación de cadenas y ProtectedResourceScopes. En el ejemplo siguiente, una solicitud GET tendrá los permisos "all.scope" y "read.scope", mientras que una solicitud PUT solo tendría "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. Valor de ámbito de null, que indica que un recurso se va a desprotegir y no obtendrá tokens. Los recursos no incluidos en protectedResourceMap no están protegidos de forma predeterminada. Especificar un recurso determinado que se va a desprotegir puede ser útil cuando se van a proteger algunas rutas de un recurso y algunas no. Tenga en cuenta que el orden en protectedResourceMap es importante, por lo que el recurso nulo debe colocarse antes de cualquier URL base similar o comodín.
{
    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"]]
    ]),
}

Otras cosas que se deben tener en cuenta con respecto a protectedResourceMap:

  • Caracteres comodín: protectedResourceMap admite el uso * de caracteres comodín. Al usar caracteres comodín, si se encuentran varias entradas coincidentes en protectedResourceMap, se usará la primera coincidencia encontrada (en función del orden de protectedResourceMap).
  • Rutas de acceso relativas: si hay rutas de acceso de recursos relativas en la aplicación, es posible que deba proporcionar la ruta de acceso relativa en protectedResourceMap. Esto también se aplica a los problemas que pueden surgir con ngx-translate. Ten en cuenta que la ruta relativa en tu protectedResourceMap puede o no necesitar una barra diagonal inicial, según tu aplicación, y puede que tengas que probar ambas opciones.

Coincidencia exacta (strictMatching)

En msal-angular v5, la coincidencia de patrones de componente URL para las entradas protectedResourceMap utiliza, por defecto, una semántica de coincidencia estricta. El strictMatching campo de MsalInterceptorConfiguration controla este comportamiento.

Importante

Si la aplicación establece las claves de protectedResourceMap dinámicamente (por ejemplo, desde archivos de entorno, APP_INITIALIZER o configuración JSON) y esas claves son direcciones URL base sin subrutas ni comodines, la coincidencia estricta puede impedir silenciosamente que el se adjunte el encabezado Authorization. Esto provoca errores 401 sin error en tiempo de compilación y sin advertencia por solicitud, solo una única advertencia de inicialización si strictMatching no está configurado explícitamente. Consulte Solución de problemas de coincidencias estrictas para obtener más información.

Cambios en la coincidencia exacta

Comportamiento Heredado (strictMatching: false) Strict (valor predeterminado en v5)
Escape de metacaracteres . y otros metacaracteres de expresiones regulares no se escapan; actúan como operadores de expresiones regulares Todos los metacaractores (incluidos .) se tratan como literales
Anclaje El patrón puede coincidir en cualquier parte de la cadena. El patrón debe coincidir con la cadena completa (^…$)
Comodín de host (*) * coincide con cualquier secuencia de caracteres, incluido . * coincide con cualquier secuencia de caracteres que no incluya . (los caracteres comodín permanecen dentro de una sola etiqueta DNS)
Comodín de ruta/búsqueda/hash (*) * coincide con cualquier secuencia de caracteres * coincide con cualquier secuencia de caracteres (sin cambios)
? carácter Se pasa a la expresión regular subyacente Tratado como un literal? (separador de la cadena de consulta de la URL, no un comodín)

Con coincidencia estricta (valor predeterminado v5):

  • Un patrón como *.contoso.com coincide con app.contoso.com pero no cona.b.contoso.com (el carácter comodín no puede abarcar separadores por puntos).
  • Un patrón como https://graph.microsoft.com/v1.0/me coincide solo con esa dirección URL exacta.

Patrones de error comunes

Los siguientes patrones de clave protectedResourceMap funcionan con la coincidencia heredada, pero fallan silenciosamente con la coincidencia estricta:

Patrón de teclas Dirección URL de solicitud saliente Resultado con coincidencia estricta Corregir
https://api.example.com https://api.example.com/v1/users No hay coincidencia — la clave se resuelve como la ruta /, la solicitud tiene la ruta /v1/users https://api.example.com/*
https://api.example.com/ https://api.example.com/v1/users No hay coincidencia: la barra final ancla el patrón exactamente a / https://api.example.com/*
environment.apiConfig.uri (por ejemplo, https://api.example.com) https://api.example.com/v1/users No coincide — igual que arriba `${environment.apiConfig.uri}/*`

Comportamiento predeterminado en la versión 5 (sin necesidad de configuración)

La coincidencia estricta está habilitada de forma predeterminada. No se requiere ninguna configuración 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
}

Exclusión de la coincidencia heredada

Si tus patrones dependen de la coincidencia menos estricta de v4, puedes configurar strictMatching: false para conservar temporalmente el comportamiento heredado:

Note

La coincidencia heredada (strictMatching: false) se ofrece por compatibilidad con versiones anteriores y puede eliminarse en una futura versión principal. Se recomienda actualizar los protectedResourceMap patrones para que funcionen con coincidencias estrictas.

{
    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
}

Guía para configuraciones controladas por el entorno

Si las claves protectedResourceMap hacen referencia a valores de Angular environment (por ejemplo, environment.apiConfig.uri), compruebe si esos valores son rutas exactas (por ejemplo, https://graph.microsoft.com/v1.0/me) o URL base simples (por ejemplo, https://api.example.com). Las rutas exactas funcionan correctamente cuando se usa una coincidencia estricta y no necesitan un tratamiento 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,
  };
}

Si el valor de entorno es una URL base simple y necesita coincidir con subrutas, añada el comodín /*:

  // 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 configuraciones verdaderamente dinámicas en las que la forma de la clave no se conoce en tiempo de compilación (por ejemplo, APP_INITIALIZER, JSON cargado mediante fetch, o platformBrowserDynamic), establece strictMatching: false como valor predeterminado temporal y seguro. Consulte Opciones de corrección: opción B para obtener un ejemplo de código.

Solución de problemas de coincidencias estrictas

Síntomas
  • Las solicitudes de API devuelven 401 No autorizado después de actualizar a @azure/msal-angular v5 (o entre versiones secundarias v5, como 5.0.x → 5.1.x).
  • El encabezado Authorization: Bearer <token>falta en las solicitudes HTTP salientes.
  • No se notifican errores en tiempo de compilación o en tiempo de ejecución: el error es silencioso.
  • El problema solo puede aparecer en determinados entornos (por ejemplo, almacenamiento provisional o producción), donde la dirección URL base de la API difiere del desarrollo.
Opciones para corregir

Opción A: Actualizar las claves para que funcionen con coincidencias estrictas (recomendado)

Actualice las claves protectedResourceMap para usar rutas de acceso exactas o caracteres comodín que coincidan con reglas de coincidencia estrictas. Este enfoque es preferible porque la coincidencia estricta es más segura y predecible:

{
    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
}

Opción B: Configurar strictMatching: false (alternativa para configuraciones dinámicas)

protectedResourceMap Si las claves se cargan dinámicamente en tiempo de ejecución (por ejemplo, desde APP_INITIALIZER, configuración JSON o platformBrowserDynamic) y no puede garantizar que contengan rutas de acceso exactas o caracteres comodín, establezca strictMatching: false como valor predeterminado seguro temporal:

{
    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

La coincidencia heredada (strictMatching: false) se ofrece por compatibilidad con versiones anteriores y puede eliminarse en una futura versión principal.

Advertencia en tiempo de ejecución

MsalInterceptor emite una advertencia en tiempo de ejecución única a través del registrador de MSAL durante la inicialización cuando strictMatching no está configurado explícitamente. Si ve esta advertencia, siga las opciones de corrección anteriores.

authRequest opcional

Para obtener más información sobre la opción authRequest que se puede establecer en MsalInterceptorConfiguration, consulte nuestra documentación para varios inquilinos aquí.

Cambios de msal-angular v1 a v2

Note

El unprotectedResourceMap elemento en MSAL Angular v1 MsalAngularConfiguration ha quedado en desuso y ya no funciona.

  • protectedResourceMap se ha movido al MsalInterceptorConfiguration objeto y se puede pasar como Map<string, Array<string|ProtectedResourceScopes>>. MsalAngularConfiguration ha quedado en desuso y ya no funciona.
  • Ya no se admite colocar el dominio raíz en protectedResourceMap para proteger todas las rutas. Use la coincidencia de caracteres comodín en su lugar.

Para obtener más información sobre cómo configurar ámbitos, consulte nuestras preguntas más frecuentes.