Compartir a través de


Evite las recargas de página al adquirir y renovar tokens en modo silencioso utilizando MSAL.js

La Biblioteca de autenticación de Microsoft para JavaScript (MSAL.js) usa elementos iframe ocultos para adquirir y renovar los tokens silenciosamente en segundo plano. Microsoft Entra ID devuelve el token a los redirect_uri registrados especificados en la solicitud de token (de forma predeterminada, es la página raíz de la aplicación). Puesto que la respuesta es 302, da como resultado el HTML correspondiente al redirect_uri que se carga en el iframe. Normalmente, el redirect_uri de la aplicación es la página raíz y esto provoca que se vuelva a cargar.

En otros casos, si ir a la página raíz de la aplicación requiere autenticación, podría provocar elementos iframe anidados o un error X-Frame-Options: deny.

Dado que MSAL.js no puede rechazar el mensaje 302 emitido por Microsoft Entra ID y es necesario para procesar el token devuelto, no puede impedir que redirect_uri se cargue en iframe.

Para evitar que toda la aplicación vuelva a cargarse de nuevo u otros errores debidos a esto, siga estas soluciones.

Especificación de HTML diferente para el iframe

Establezca la redirect_uri propiedad en config en una página sencilla, que no requiere autenticación. Debe asegurarse de que coincide con el redirect_uri registrado en el Centro de administración de Microsoft Entra. Esto no afectará a la experiencia de inicio de sesión del usuario, ya que MSAL guarda la página de inicio cuando el usuario comienza el proceso de inicio de sesión y vuelve a redirigirse a la ubicación exacta una vez completado el inicio de sesión.

Inicialización en el archivo de aplicación principal

Si la aplicación está estructurada de forma que hay un archivo de JavaScript central que define la inicialización de la aplicación, el enrutamiento y otras cuestiones, puede cargar condicionalmente los módulos de aplicación en función de si la aplicación se está cargando en un iframe o no. Por ejemplo:

En 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
            );
        }]);
}

En 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);
    }
  }
}

MsalComponente:

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

Pasos siguientes

Para aprender más, cree una aplicación de página única (SPA) de React que permita a los usuarios iniciar sesión en la siguiente serie de tutoriales de varias partes.