Intercepteur MSAL

MSAL Angular fournit une Interceptor classe qui acquiert automatiquement des jetons pour les requêtes sortantes qui utilisent le client Angular http pour les ressources protégées connues. Ce document fournit plus d’informations sur la configuration et l’utilisation du MsalInterceptorfichier .

Bien que nous vous recommandions d’utiliser MsalInterceptor plutôt que l’API acquireTokenSilent directement, veuillez noter que l’utilisation de MsalInterceptor est facultative. Vous souhaiterez peut-être acquérir explicitement des jetons à l’aide des API acquireToken à la place.

Notez que l’option MsalInterceptor est fournie pour votre commodité et peut ne pas correspondre à tous les cas d’usage. Nous vous encourageons à écrire votre propre intercepteur si vous avez des besoins spécifiques qui ne sont pas couverts par le MsalInterceptor.

Configuration

Configuration du MsalInterceptor dans le app.module.ts

Le MsalInterceptor peut être ajouté à votre application en tant que fournisseur dans app.module.ts, avec sa configuration associée. Les imports incluent une instance de MSAL, ainsi que deux objets de configuration spécifiques à Angular. Le troisième argument est un MsalInterceptorConfiguration objet, qui contient les valeurs pour interactionType, a protectedResourceMapet facultatif authRequest.

Votre configuration peut ressembler à ce qui suit. Consultez notre documentation de configuration sur d’autres façons de configurer MSAL Angular pour votre application.

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

Type d’interaction

Bien que MsalInterceptor soit conçu pour obtenir des jetons en mode silencieux, en cas d’échec d’une demande silencieuse, il se rabat sur une obtention interactive des jetons. Le InteractionType peut être importé depuis @azure/msal-browser et être défini sur Popup ou Redirect.

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

Carte des ressources protégée

Les ressources protégées et les étendues correspondantes sont fournies sous la forme d’une protectedResourceMapMsalInterceptor configuration.

Les URL que vous fournissez dans la collection protectedResourceMap sont sensibles à la casse. Pour chaque ressource, ajoutez les étendues à retourner dans le jeton d’accès.

Par exemple:

  • ["user.read"] pour Microsoft Graph
  • ["<Application ID URL>/scope"] pour les API web personnalisées (autrement dit, api://<Application ID>/access_as_user)

Les étendues peuvent être spécifiées pour une ressource de la manière suivante :

  1. Ensemble de portées ajouté à chaque requête HTTP adressée à cette ressource, quelle que soit la méthode 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. Un tableau de ProtectedResourceScopes, qui n’appliquera des portées qu’à des méthodes HTTP spécifiques.
{
    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"]
            }
        ]]
    ])
}

Notez que les étendues d’une ressource peuvent contenir une combinaison de chaînes et ProtectedResourceScopes. Dans l’exemple ci-dessous, une GET requête aura les étendues "all.scope" et "read.scope", alors que la PUT demande aurait simplement "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. Valeur de portée de null, indiquant qu’une ressource ne doit pas être protégée et ne recevra pas de jetons. Les ressources non incluses dans le fichier protectedResourceMap ne sont pas protégées par défaut. La spécification d’une ressource particulière à ne pas protéger peut être utile lorsque certains itinéraires d’une ressource doivent être protégés, et certains ne le sont pas. Notez que l’ordre dans protectedResourceMap est important ; la ressource null doit donc être placée avant toute URL de base similaire ou caractère générique.
{
    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"]]
    ]),
}

Autres points à noter concernant le protectedResourceMap :

  • Caractères génériques : protectedResourceMap prend en charge l’utilisation * pour les caractères génériques. Lorsque vous utilisez des caractères génériques, si plusieurs entrées correspondantes sont trouvées dans le protectedResourceMap, la première correspondance trouvée est utilisée (en fonction de l’ordre du protectedResourceMap).
  • Chemins relatifs : s’il existe des chemins de ressources relatifs dans votre application, vous devrez peut-être fournir le chemin relatif dans le protectedResourceMap. Cela s’applique également aux problèmes qui peuvent survenir avec ngx-translate. Sachez que le chemin relatif dans votre protectedResourceMap peut nécessiter ou non une barre oblique initiale selon votre application, et qu'il peut être nécessaire d'essayer les deux.

Correspondance exacte (strictMatching)

Dans msal-angular v5, la correspondance des modèles de composants d'URL pour les entrées protectedResourceMap utilise par défaut une sémantique de correspondance stricte. Le champ strictMatching sur MsalInterceptorConfiguration contrôle ce comportement.

Important

Si votre application définit dynamiquement des clés protectedResourceMap (par exemple, à partir de fichiers d’environnement, de APP_INITIALIZER ou d’une configuration JSON) et que ces clés sont des URL de base sans sous-chemins ni caractères génériques, la correspondance stricte peut empêcher l’en-tête Authorization d’être ajouté sans avertissement. Cela entraîne des erreurs 401 sans erreur à la compilation et sans aucun avertissement pour chaque requête — uniquement un avertissement d’initialisation unique si strictMatching n’est pas explicitement configuré. Pour plus d’informations, consultez résolution des problèmes de correspondance stricte .

Ce que change la correspondance stricte

Behavior Hérité (strictMatching: false) Strict (valeur par défaut dans v5)
Échappement des métacaractères . et les autres métacaractères regex ne sont pas échappés ; ils agissent comme des opérateurs regex. Tous les métacaractères (y compris .) sont considérés comme littéraux
Ancrage Le modèle peut correspondre n’importe où dans la chaîne Le modèle doit correspondre à la chaîne complète (^…$)
Caractère générique d'hôte (*) * correspond à n’importe quelle séquence de caractères, y compris . * correspond à n'importe quelle séquence de caractères qui n'inclut pas . (les caractères génériques restent dans un seul label DNS).
Caractère générique de chemin/recherche/hachage (*) * correspond à n’importe quelle séquence de caractères * correspond à n’importe quelle séquence de caractères (inchangée)
? personnage Transmis à l’expression régulière sous-jacente Traité comme un littéral? (séparateur de chaîne de requête d'URL, et non caractère générique)

Avec une correspondance stricte (la valeur par défaut v5) :

  • Un modèle comme *.contoso.com correspond à app.contoso.com, mais pasa.b.contoso.com (le caractère générique ne peut pas couvrir les séparateurs de points).
  • Un modèle semblable https://graph.microsoft.com/v1.0/me ne correspond qu’à cette URL exacte.

Schémas d’échec courants

Les modèles de clés protectedResourceMap suivants fonctionnent avec la correspondance héritée, mais échouent silencieusement avec la correspondance stricte :

Modèle clé URL de requête sortante Résultat avec correspondance stricte Réparer
https://api.example.com https://api.example.com/v1/users Aucune correspondance — la clé se résout en chemin /, la requête a pour chemin /v1/users https://api.example.com/*
https://api.example.com/ https://api.example.com/v1/users Aucune correspondance — la barre oblique finale ancre le modèle exactement sur /. https://api.example.com/*
environment.apiConfig.uri (par exemple, https://api.example.com) https://api.example.com/v1/users Aucune correspondance , identique à celle ci-dessus `${environment.apiConfig.uri}/*`

Comportement par défaut dans v5 (aucune configuration nécessaire)

La correspondance stricte est activée par défaut. Aucune configuration supplémentaire n’est requise :

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

Désactivation au profit de la correspondance héritée

Si vos modèles s’appuient sur la correspondance plus libre de v4, vous pouvez définir strictMatching: false pour conserver temporairement le comportement hérité :

Note

La correspondance héritée (strictMatching: false) est fournie pour assurer la rétrocompatibilité et pourra être supprimée dans une future version majeure. Nous vous recommandons de mettre à jour vos protectedResourceMap modèles pour qu’ils fonctionnent avec une correspondance stricte.

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

Conseils pour les configurations pilotées par l’environnement

Si vos protectedResourceMap clés référencent des valeurs Angular environment (par exemple), environment.apiConfig.urivérifiez si ces valeurs sont des chemins exacts (par exemple) https://graph.microsoft.com/v1.0/meou des URL de base nues (par exemple). https://api.example.com Les chemins exacts fonctionnent correctement avec une correspondance stricte et n’ont pas besoin d’une gestion spéciale :

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 la valeur d'environnement est une URL de base nue et que vous devez faire correspondre des sous-chemins, ajoutez un caractère générique /* :

  // 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);

Pour les configurations véritablement dynamiques où la forme clé n’est pas connue au moment de la génération (par exemple, APP_INITIALIZER, JSON chargé via fetchou platformBrowserDynamic), définie strictMatching: false comme valeur par défaut sécurisée temporaire. Consultez les options de correction : option B pour obtenir un exemple de code.

Résolution des problèmes de correspondance stricte

Symptoms
  • Les demandes d’API retournent 401 Non autorisé après la mise à niveau vers @azure/msal-angular v5 (ou entre les versions mineures v5 telles que 5.0.x → 5.1.x).
  • L’en-tête Authorization: Bearer <token> est manquant dans les requêtes HTTP sortantes.
  • Aucune erreur d’exécution ou de temps de génération n’est signalée : l’échec est silencieux.
  • Le problème peut apparaître uniquement dans certains environnements (par exemple, préproduction/production) où l’URL de base de l’API diffère du développement.
Options de correction

Option A : Mettre à jour les clés pour qu’elles fonctionnent avec une correspondance stricte (recommandé)

Mettez à jour vos clés protectedResourceMap pour utiliser des chemins exacts ou des caractères génériques correspondant aux règles de correspondance stricte. Cette approche est préférée, car la correspondance stricte est plus sûre et plus prévisible :

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

Option B : Définir strictMatching: false (solution de repli pour les configurations dynamiques)

Si vos clés protectedResourceMap sont chargées dynamiquement à l’exécution (par exemple, depuis APP_INITIALIZER, une configuration JSON ou platformBrowserDynamic) et que vous ne pouvez pas garantir qu’elles contiennent des chemins exacts ou des caractères génériques, définissez strictMatching: false comme valeur sûre par défaut à titre temporaire :

{
    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 correspondance héritée (strictMatching: false) est fournie pour assurer la rétrocompatibilité et pourra être supprimée dans une future version majeure.

Avertissement d'exécution

MsalInterceptor émet un avertissement d’exécution unique via l’enregistreur d’événements MSAL lors de l’initialisation lorsqu’il strictMatching n’est pas configuré explicitement. Si vous voyez cet avertissement, suivez les options de correctif ci-dessus.

AuthRequest facultative

Pour plus d'informations sur le authRequest facultatif pouvant être défini dans le MsalInterceptorConfiguration, veuillez consulter notre documentation multilocataire ici.

Modifications entre msal-angular v1 et v2

Note

Le unprotectedResourceMap dans le MsalAngularConfiguration de MSAL Angular v1 a été déprécié et ne fonctionne plus.

  • protectedResourceMap a été déplacé vers l’objet MsalInterceptorConfiguration et peut être passé en tant que Map<string, Array<string|ProtectedResourceScopes>>. MsalAngularConfiguration a été déconseillé et ne fonctionne plus.
  • Placer le domaine racine dans le protectedResourceMap pour protéger toutes les routes n'est plus pris en charge. Veuillez utiliser la correspondance avec caractères génériques à la place.

Pour plus d’informations sur la façon de configurer les portées, veuillez consulter notre FAQ.