Condividi tramite


Evitare il ricaricamento delle pagine durante l'acquisizione e il rinnovo dei token in modo invisibile all'utente tramite MSAL.js

La Microsoft Authentication Library per JavaScript (MSAL.js) utilizza elementi iframe nascosti per acquisire e rinnovare i token silenziosamente in background. Microsoft Entra ID restituisce il token al redirect_uri registrato specificato nella richiesta di token(per impostazione predefinita si tratta della pagina radice dell'app). Poiché la risposta è 302, viene restituito il codice HTML corrispondente al redirect_uri caricato nel iframe. In genere, la pagina radice dell'app redirect_uri è quella di partenza e ciò comporta il ricaricamento.

In altri casi, se passare alla pagina radice dell'app richiede l'autenticazione, potrebbe causare elementi annidati iframe o errore X-Frame-Options: deny.

Poiché MSAL.js non può ignorare il 302 emesso da Microsoft Entra ID ed è necessario per elaborare il token restituito, non può impedire che redirect_uri sia caricato nel iframe.

Per evitare il ricaricamento dell'intera app o altri errori causati da questo problema, seguire queste soluzioni alternative.

Specificare codice HTML diverso per l'iframe

Impostare la proprietà redirect_uri nella configurazione su una pagina semplice, che non richiede l'autenticazione. È necessario assicurarsi che corrisponda al redirect_uri registrato nell'interfaccia di amministrazione di Microsoft Entra. Ciò non influisce sull'esperienza di accesso dell'utente perché MSAL salva la pagina iniziale quando l'utente avvia il processo di accesso e reindirizza alla posizione esatta dopo il completamento dell'accesso.

Inizializzazione nel file principale dell'app

Se l'app è strutturata in modo che sia presente un file JavaScript centrale che definisce l'inizializzazione, il routing e altri elementi dell'app, è possibile caricare in modo condizionale i moduli dell'app in base al caricamento dell'app in un iframe o meno. Per esempio:

In AngularJS: app.js

// Check that the window is an iframe and not popup
if (window !== window.parent && !window.opener) {
angular.module('todoApp', ['ui.router', 'MsalAngular'])
    .config(['$httpProvider', 'msalAuthenticationServiceProvider','$locationProvider', function ($httpProvider, msalProvider,$locationProvider) {
        msalProvider.init(
            // msal configuration
        );

        $locationProvider.html5Mode(false).hashPrefix('');
    }]);
}
else {
    angular.module('todoApp', ['ui.router', 'MsalAngular'])
        .config(['$stateProvider', '$httpProvider', 'msalAuthenticationServiceProvider', '$locationProvider', function ($stateProvider, $httpProvider, msalProvider, $locationProvider) {
            $stateProvider.state("Home", {
                url: '/Home',
                controller: "homeCtrl",
                templateUrl: "/App/Views/Home.html",
            }).state("TodoList", {
                url: '/TodoList',
                controller: "todoListCtrl",
                templateUrl: "/App/Views/TodoList.html",
                requireLogin: true
            })

            $locationProvider.html5Mode(false).hashPrefix('');

            msalProvider.init(
                // msal configuration
            );
        }]);
}

In Angular: app.module.ts

// Imports...
@NgModule({
  declarations: [
    AppComponent,
    MsalComponent,
    MainMenuComponent,
    AccountMenuComponent,
    OsNavComponent
  ],
  imports: [
    BrowserModule,
    AppRoutingModule,
    HttpClientModule,
    ServiceWorkerModule.register('ngsw-worker.js', { enabled: environment.production }),
    MsalModule.forRoot(environment.MsalConfig),
    SuiModule,
    PagesModule
  ],
  providers: [
    HttpServiceHelper,
    {provide: HTTP_INTERCEPTORS, useClass: MsalInterceptor, multi: true},
    AuthService
  ],
  entryComponents: [
    AppComponent,
    MsalComponent
  ]
})
export class AppModule {
  constructor() {
    console.log('APP Module Constructor!');
  }

  ngDoBootstrap(ref: ApplicationRef) {
    if (window !== window.parent && !window.opener)
    {
      console.log("Bootstrap: MSAL");
      ref.bootstrap(MsalComponent);
    }
    else
    {
    //this.router.resetConfig(RouterModule);
      console.log("Bootstrap: App");
      ref.bootstrap(AppComponent);
    }
  }
}

MsalComponent:

import { Component} from '@angular/core';
import { MsalService } from '@azure/msal-angular';

// This component is used only to avoid Angular reload
// when doing acquireTokenSilent()

@Component({
  selector: 'app-root',
  template: '',
})
export class MsalComponent {
  constructor(private Msal: MsalService) {
  }
}

Passaggi successivi

Per ulteriori informazioni, prova a creare un'applicazione React a pagina singola (SPA) che permette agli utenti di effettuare l'accesso nella seguente serie di esercitazioni in più parti .