Angular 路由与 Msal Azure AD 集成

Angular routing with Msal Azure AD integration

我在 Angular 13,使用 MSAL 与 Azure AD 集成。我的问题是一旦用户成功登录,logincomponent 就不会显示。但是,当我刷新页面时,会显示登录组件。如何让登录组件在用户登录后立即显示。

在实现调试时,在 AuthGaurd 启动时登录时,即使登录成功,此 this.msalsvc.instance.getActiveAccount() returns 仍为 null

这是我的应用路由,

import { NgModule } from '@angular/core';
import { RouterModule, Routes } from '@angular/router';
import { AuthGuard } from './auth-guard.guard';
import { LoginComponent } from './components/login/login/login.component';
import { TestComponent } from './components/test/test.component';
import { RoleGuard } from './route-guard.guard';


const routes: Routes =[
  {path: '', component: TestComponent, canActivate: [AuthGuard]}
]

@NgModule({
  imports: [RouterModule.forRoot(routes)],
  exports: [RouterModule]
})
export class AppRoutingModule { }

这是我的app.component.html

<app-header></app-header>

  <div *ngIf="IsLoggedIn()">
    <h3>Welcome {{userName}}</h3>
    <h3>Your Assigned role: {{userRole}}</h3>
  </div>
  <div *ngIf="!IsLoggedIn()">
    <h3>You are NOT logged in</h3>
  </div>

<router-outlet></router-outlet>
<app-footer></app-footer>

这是 Auth Guard 的代码

import { Injectable } from '@angular/core';
import { ActivatedRouteSnapshot, CanActivate, CanActivateChild, RouterStateSnapshot, UrlTree } from '@angular/router';
import { MsalService } from '@azure/msal-angular';
import { map, Observable, Subscription } from 'rxjs';
import { CommonService } from './services/common-service.service';

@Injectable({
  providedIn: 'root'
})
export class AuthGuard implements CanActivate{
 
  constructor(private msalsvc : MsalService){
  }

  canActivate(
    route: ActivatedRouteSnapshot,
    state: RouterStateSnapshot): boolean {
      console.log('Hi there, ');
 
    if(this.msalsvc.instance.getActiveAccount() == null){
      return false;
    }
    return true;
  }

  
}

这是添加登录方法的普通服务

import { Injectable } from '@angular/core';
import { MsalService } from '@azure/msal-angular';
import { AuthenticationResult } from '@azure/msal-browser';
import { observable, Observable, Subject,of} from 'rxjs';

@Injectable({
  providedIn: 'root'
})
export class CommonService {

  //private loggedIn : boolean = false;
   private subject = new Subject<any>();
  constructor(private authService: MsalService) {
    console.info('Common service is created');
   }
   
   login() {
    this.authService.loginPopup()
      .subscribe((response: AuthenticationResult) => {
        this.authService.instance.setActiveAccount(response.account);
        this.updateLoginNotification(true);
      });
  }

  isLoggedIn(): boolean {
    return this.authService.instance.getActiveAccount() != null
  }

  isAsyncLoggedIn():Observable<boolean>{
    return of(this.authService.instance.getActiveAccount() !=null);
  }
  
  onLoginCheck(): Observable<boolean>{
     return this.subject.asObservable();
   }
  
   getName():any{
    this.getRole();
    return this.authService.instance.getActiveAccount()?.name;
  }
   getRole():any{
     return (this.authService.instance.getActiveAccount()?.idTokenClaims as any).roles;
   }
   updateLoginNotification(item: any) { 
    this.subject.next(item);
}

}

调用 login() 并确保它成功完成后,使用 Router 服务导航到正确的路径。这将导致身份验证守卫在登录后触发。

为了确保登录完成,您应该return在login()函数中创建的observable。

在common.service.ts中:

  login(): Observable<AuthenticationResult> {
    const observable = this.authService.loginPopup();
    observable.subscribe((response: AuthenticationResult) => {
      this.authService.instance.setActiveAccount(response.account);
      this.updateLoginNotification(true);
    });
    return observable;
  }

现在,在调用 login() 后,您可以在 登录 后路由到正确的路径。

在app.component.ts中:

  constructor(private router: Router, private loginService: LoginService) {}

  login() {
    const obs = this.loginService.login();
    obs.subscribe((result) => {
      //Check that the login was successful here
      const success = true;
      if (success) this.router.navigate(['yourPathHere']);
    });
  }

现在您知道用户在尝试加载页面之前已登录。 auth guard 只是作为一种预防措施存在,例如当用户使用 url.

手动导航时