Aracılığıyla paylaş


Öğretici: Kimlik doğrulama kod akışını kullanarak kullanıcıları oturum açma ve Angular tek sayfalı uygulamadan (SPA) Microsoft Graph API'sini çağırma

Bu öğreticide, kullanıcılarda oturum açıp PKCE ile yetkilendirme kodu akışını kullanarak Microsoft Graph API'sini çağıran bir Angular tek sayfalı uygulama (SPA) oluşturacaksınız. Oluşturduğunuz SPA, Angular v2 için Microsoft Kimlik Doğrulama Kitaplığı'nı (MSAL) kullanır.

Bu öğreticide:

  • Uygulamayı Microsoft Entra yönetim merkezine kaydetme
  • ile Angular projesi oluşturma npm
  • Kullanıcı oturum açma ve oturum kapatmayı desteklemek için kod ekleme
  • Microsoft Graph API'sini çağırmak için kod ekleme
  • Uygulamayı test etme

MSAL Angular v2, kimlik doğrulama kodu akışını örtük verme akışı yerine tarayıcıda PKCE ile destekleyerek MSAL Angular v1'de geliştirir. Tek sayfalı uygulamalar (SPA' lar) için PKCE ile yetkilendirme kodu akışını kullanmanızı öneririz çünkü örtük akıştan daha güvenlidir. MSAL Angular v2 örtük akışı DESTEKLEMEZ .

Önkoşullar

Örnek uygulama nasıl çalışır?

Tek sayfalı bir uygulamada yetkilendirme kodu akışını gösteren diyagram

Bu öğreticide oluşturulan örnek uygulama, Angular SPA'nın Microsoft Graph API'sini veya Microsoft kimlik platformu tarafından verilen belirteçleri kabul eden bir web API'sini sorgulamasını sağlar. MSAL.js v2 kitaplığının sarmalayıcısı olan Angular v2 için Microsoft Kimlik Doğrulama Kitaplığı'nı (MSAL) kullanır. MSAL Angular, Angular 9+ uygulamalarının Microsoft Entra ID kullanarak kurumsal kullanıcıların ve ayrıca Microsoft hesapları ve Facebook, Google ve LinkedIn gibi sosyal kimliklere sahip kullanıcıların kimliğini doğrulamasını sağlar. Kitaplık ayrıca uygulamaların Microsoft bulut hizmetlerine ve Microsoft Graph'a erişmesini sağlar.

Bu senaryoda, bir kullanıcı oturum açtığında, yetkilendirme üst bilgisi aracılığıyla bir erişim belirteci istenir ve HTTP isteklerine eklenir. Belirteç alma ve yenileme MSAL tarafından işlenir.

Kitaplıklar

Bu öğreticide aşağıdaki kitaplıklar kullanılır:

Kitaplık Açıklama
MSAL Angular JavaScript Angular Sarmalayıcısı için Microsoft Kimlik Doğrulama Kitaplığı
MSAL Tarayıcısı JavaScript v2 tarayıcı paketi için Microsoft Kimlik Doğrulama Kitaplığı

Tüm MSAL.js kitaplıklarının kaynak kodunu GitHub'daki depoda microsoft-authentication-library-for-js bulabilirsiniz.

Tamamlanmış kod örneğini alma

Bunun yerine bu öğretici için tamamlanmış örnek projeyi indirmeyi tercih ediyor musunuz? ms-identity-javascript-angular-spa'yı kopyalama

git clone https://github.com/Azure-Samples/ms-identity-javascript-angular-spa.git

Öğreticiye devam etmek ve uygulamayı kendiniz oluşturmak için, uygulamayı kaydetme ve kayıt tanımlayıcıları başlıklı sonraki bölüme geçin.

Uygulama ve kayıt tanımlayıcılarını kaydetme

İpucu

Bu makaledeki adımlar, başladığınız portala göre biraz değişiklik gösterebilir.

Kaydı tamamlamak için uygulamaya bir ad verin, desteklenen hesap türlerini belirtin ve yeniden yönlendirme URI'sini ekleyin. Kaydedildikten sonra, uygulamaya Genel Bakış bölmesinde uygulama kaynak kodunda gereken tanımlayıcılar görüntülenir.

  1. Microsoft Entra yönetim merkezinde en azından Uygulama Geliştiricisi olarak oturum açın.
  2. Birden çok kiracıya erişiminiz varsa, dizinler + abonelikler menüsünden uygulamayı kaydetmek istediğiniz kiracıya geçmek için üst menüdeki Ayarlar simgesini kullanın.
  3. Kimlik>Uygulamaları'na> göz atın Uygulama kayıtları.
  4. Yeni kayıt öğesini seçin.
  5. Uygulama için Angular-SPA-auth-code gibi bir Ad girin.
  6. Desteklenen hesap türleri için Yalnızca bu kuruluş dizinindeki Hesaplar'ı seçin. Farklı hesap türleri hakkında bilgi için Bana yardım et seçeneğini belirleyin.
  7. Yeniden Yönlendirme URI'sinin (isteğe bağlı) altında, açılan menüyü kullanarak Tek sayfalı uygulama (SPA) öğesini seçin ve metin kutusuna girinhttp://localhost:4200.
  8. Kaydet'i seçin.
  9. Kayıt tamamlandığında uygulamanın Genel Bakış bölmesi görüntülenir. Uygulama kaynak kodunuzda kullanılacak Dizin (kiracı) kimliğini ve Uygulama (istemci) kimliğini kaydedin.

Projenizi oluşturun

  1. Visual Studio Code'ı açın, Dosya>Klasör Aç... öğesini seçin. Adresine gidin ve projenizin oluşturulacağı konumu seçin.

  2. Terminal>Yeni Terminal'i seçerek yeni bir terminal açın.

    1. Terminal türlerini değiştirmeniz gerekebilir. Terminaldeki simgenin + yanındaki aşağı oku ve ardından Komut İstemi'ni seçin.
  3. adlı msal-angular-tutorialyeni bir Angular projesi oluşturmak için aşağıdaki komutları çalıştırın, Angular Malzeme bileşen kitaplıklarını, MSAL Browser'ı, MSAL Angular'ı yükleyin ve ev ve profil bileşenleri oluşturun.

    npm install -g @angular/cli
    ng new msal-angular-tutorial --routing=true --style=css --strict=false
    cd msal-angular-tutorial
    npm install @angular/material @angular/cdk
    npm install @azure/msal-browser @azure/msal-angular
    ng generate component home
    ng generate component profile
    

Uygulamayı yapılandırma ve temel kullanıcı arabirimini düzenleme

  1. src/app/app.module.ts açın. ve öğesinin MsalModule sabitle isIE birlikte eklenmesi importsMsalInterceptor gerekir. Ayrıca malzeme modüllerini de ekleyeceksiniz. Dosyanın tüm içeriğini aşağıdaki kod parçacığıyla değiştirin:

    import { BrowserModule } from "@angular/platform-browser";
    import { BrowserAnimationsModule } from "@angular/platform-browser/animations";
    import { NgModule } from "@angular/core";
    
    import { MatButtonModule } from "@angular/material/button";
    import { MatToolbarModule } from "@angular/material/toolbar";
    import { MatListModule } from "@angular/material/list";
    
    import { AppRoutingModule } from "./app-routing.module";
    import { AppComponent } from "./app.component";
    import { HomeComponent } from "./home/home.component";
    import { ProfileComponent } from "./profile/profile.component";
    
    import { MsalModule, MsalRedirectComponent } from "@azure/msal-angular";
    import { PublicClientApplication } from "@azure/msal-browser";
    
    const isIE =
      window.navigator.userAgent.indexOf("MSIE ") > -1 ||
      window.navigator.userAgent.indexOf("Trident/") > -1;
    
    @NgModule({
      declarations: [AppComponent, HomeComponent, ProfileComponent],
      imports: [
        BrowserModule,
        BrowserAnimationsModule,
        AppRoutingModule,
        MatButtonModule,
        MatToolbarModule,
        MatListModule,
        MsalModule.forRoot(
          new PublicClientApplication({
            auth: {
              clientId: "Enter_the_Application_Id_here", // Application (client) ID from the app registration
              authority:
                "Enter_the_Cloud_Instance_Id_Here/Enter_the_Tenant_Info_Here", // The Azure cloud instance and the app's sign-in audience (tenant ID, common, organizations, or consumers)
              redirectUri: "Enter_the_Redirect_Uri_Here", // This is your redirect URI
            },
            cache: {
              cacheLocation: "localStorage",
              storeAuthStateInCookie: isIE, // Set to true for Internet Explorer 11
            },
          }),
          null,
          null
        ),
      ],
      providers: [],
      bootstrap: [AppComponent, MsalRedirectComponent],
    })
    export class AppModule {}
    
  2. Aşağıdaki değerleri Microsoft Entra yönetim merkezinden alınan değerlerle değiştirin. Kullanılabilir yapılandırılabilir seçenekler hakkında daha fazla bilgi için bkz . İstemci uygulamalarını başlatma.

    • clientId - İstemci olarak da adlandırılan uygulamanın tanımlayıcısı. değerini, kayıtlı uygulamanın genel bakış sayfasından daha önce kaydedilen Uygulama (istemci) Kimliği değeriyle değiştirinEnter_the_Application_Id_Here.
    • authority - Bu iki bölümden oluşur:
      • Örnek, bulut sağlayıcısının uç noktasıdır. Ana veya genel Azure bulutu için girin https://login.microsoftonline.com. Ulusal bulutlardaki farklı kullanılabilir uç noktaları denetleyin.
      • Kiracı Kimliği, uygulamanın kayıtlı olduğu kiracının tanımlayıcısıdır. değerini_Enter_the_Tenant_Info_Here, kayıtlı uygulamanın genel bakış sayfasından daha önce kaydedilen Dizin (kiracı) kimliği değeriyle değiştirin.
    • redirectUri - uygulama başarıyla yetkilendirildikten ve yetkilendirme kodu veya erişim belirteci verildikten sonra yetkilendirme sunucusunun kullanıcıyı gönderdiği konum. Enter_the_Redirect_Uri_Here öğesini http://localhost:4200 ile değiştirin.
  3. src/app/app-routing.module.ts açın ve giriş ve profil bileşenlerine yollar ekleyin. Dosyanın tüm içeriğini aşağıdaki kod parçacığıyla değiştirin:

    import { NgModule } from "@angular/core";
    import { Routes, RouterModule } from "@angular/router";
    import { BrowserUtils } from "@azure/msal-browser";
    import { HomeComponent } from "./home/home.component";
    import { ProfileComponent } from "./profile/profile.component";
    
    const routes: Routes = [
      {
        path: "profile",
        component: ProfileComponent,
      },
      {
        path: "",
        component: HomeComponent,
      },
    ];
    
    const isIframe = window !== window.parent && !window.opener;
    
    @NgModule({
      imports: [
        RouterModule.forRoot(routes, {
          // Don't perform initial navigation in iframes or popups
          initialNavigation:
            !BrowserUtils.isInIframe() && !BrowserUtils.isInPopup()
              ? "enabledNonBlocking"
              : "disabled", // Set to enabledBlocking to use Angular Universal
        }),
      ],
      exports: [RouterModule],
    })
    export class AppRoutingModule {}
    
  4. src/app/app.component.html açın ve var olan kodu aşağıdakilerle değiştirin:

    <mat-toolbar color="primary">
      <a class="title" href="/">{{ title }}</a>
    
      <div class="toolbar-spacer"></div>
    
      <a mat-button [routerLink]="['profile']">Profile</a>
    
      <button mat-raised-button *ngIf="!loginDisplay" (click)="login()">Login</button>
    
    </mat-toolbar>
    <div class="container">
      <!--This is to avoid reload during acquireTokenSilent() because of hidden iframe -->
      <router-outlet *ngIf="!isIframe"></router-outlet>
    </div>
    
  5. CSS'yi tanımlamak için src/style.css açın:

    @import "~@angular/material/prebuilt-themes/deeppurple-amber.css";
    
    html,
    body {
      height: 100%;
    }
    body {
      margin: 0;
      font-family: Roboto, "Helvetica Neue", sans-serif;
    }
    .container {
      margin: 1%;
    }
    
  6. Uygulamaya CSS stili eklemek için src/app/app.component.css açın:

    .toolbar-spacer {
      flex: 1 1 auto;
    }
    
    a.title {
      color: white;
    }
    

Açılır pencereleri kullanarak oturum açma

  1. src/app/app.component.ts dosyasını açın ve açılır pencere kullanarak bir kullanıcıda oturum açmak için dosyanın içeriğini aşağıdakiyle değiştirin:

    import { MsalService } from '@azure/msal-angular';
    import { Component, OnInit } from '@angular/core';
    
    @Component({
      selector: 'app-root',
      templateUrl: './app.component.html',
      styleUrls: ['./app.component.css']
    })
    export class AppComponent implements OnInit {
      title = 'msal-angular-tutorial';
      isIframe = false;
      loginDisplay = false;
    
      constructor(private authService: MsalService) { }
    
      ngOnInit() {
        this.isIframe = window !== window.parent && !window.opener;
      }
    
      login() {
        this.authService.loginPopup()
          .subscribe({
            next: (result) => {
              console.log(result);
              this.setLoginDisplay();
            },
            error: (error) => console.log(error)
          });
      }
    
      setLoginDisplay() {
        this.loginDisplay = this.authService.instance.getAllAccounts().length > 0;
      }
    }
    

Yeniden yönlendirmeleri kullanarak oturum açma

  1. src/app/app.module.ts'ı önyüklemek için güncelleştirin.MsalRedirectComponent Bu, yeniden yönlendirmeleri işleyen ayrılmış bir yeniden yönlendirme bileşenidir. MsalModule İçeri aktarma ve AppComponent önyükleme ayarlarını aşağıdakine benzer şekilde değiştirin:

    ...
    import { MsalModule, MsalRedirectComponent } from '@azure/msal-angular'; // Updated import
    ...
      bootstrap: [AppComponent, MsalRedirectComponent] // MsalRedirectComponent bootstrapped here
    ...
    
  2. src/index.html açın ve dosyanın tüm içeriğini seçiciyi ekleyen <app-redirect> aşağıdaki kod parçacığıyla değiştirin:

    <!doctype html>
    <html lang="en">
    <head>
      <meta charset="utf-8">
      <title>msal-angular-tutorial</title>
      <base href="/">
      <meta name="viewport" content="width=device-width, initial-scale=1">
      <link rel="icon" type="image/x-icon" href="favicon.ico">
    </head>
    <body>
      <app-root></app-root>
      <app-redirect></app-redirect>
    </body>
    </html>
    
  3. src/app/app.component.ts açın ve tam çerçeve yeniden yönlendirme kullanarak bir kullanıcıda oturum açmak için kodu aşağıdakilerle değiştirin:

    import { MsalService } from '@azure/msal-angular';
    import { Component, OnInit } from '@angular/core';
    
    @Component({
      selector: 'app-root',
      templateUrl: './app.component.html',
      styleUrls: ['./app.component.css']
    })
    export class AppComponent implements OnInit {
      title = 'msal-angular-tutorial';
      isIframe = false;
      loginDisplay = false;
    
      constructor(private authService: MsalService) { }
    
      ngOnInit() {
        this.isIframe = window !== window.parent && !window.opener;
      }
    
      login() {
        this.authService.loginRedirect();
      }
    
      setLoginDisplay() {
        this.loginDisplay = this.authService.instance.getAllAccounts().length > 0;
      }
    }
    
  4. src/app/home/home.component.ts adresine gidin ve olaya abone olmak LOGIN_SUCCESS için dosyanın tüm içeriğini aşağıdaki kod parçacığıyla değiştirin:

    import { Component, OnInit } from '@angular/core';
    import { MsalBroadcastService, MsalService } from '@azure/msal-angular';
    import { EventMessage, EventType, InteractionStatus } from '@azure/msal-browser';
    import { filter } from 'rxjs/operators';
    
    @Component({
      selector: 'app-home',
      templateUrl: './home.component.html',
      styleUrls: ['./home.component.css']
    })
    export class HomeComponent implements OnInit {
      constructor(private authService: MsalService, private msalBroadcastService: MsalBroadcastService) { }
    
      ngOnInit(): void {
        this.msalBroadcastService.msalSubject$
          .pipe(
            filter((msg: EventMessage) => msg.eventType === EventType.LOGIN_SUCCESS),
          )
          .subscribe((result: EventMessage) => {
            console.log(result);
          });
      }
    }
    

Koşullu işleme

Belirli Kullanıcı Arabirimini (UI) yalnızca kimliği doğrulanmış kullanıcılar için işlemek için, bileşenlerin kullanıcıların oturum açıp açmadığını ve etkileşimin MsalBroadcastService tamamlanıp tamamlanmadığını görmek için öğesine abone olması gerekir.

  1. MsalBroadcastServicesrc/app/app.component.ts öğesine ekleyin ve kullanıcı arabirimini işlemeden önce etkileşimin inProgress$ tamamlanıp tamamlanmadiğini ve bir hesabın oturum açıp açmadiğini denetlemek için gözlemlenebilir öğesine abone olun. Kodunuz şimdi şöyle görünmelidir:

    import { Component, OnInit, OnDestroy } from '@angular/core';
    import { MsalService, MsalBroadcastService } from '@azure/msal-angular';
    import { InteractionStatus } from '@azure/msal-browser';
    import { Subject } from 'rxjs';
    import { filter, takeUntil } from 'rxjs/operators';
    
    @Component({
      selector: 'app-root',
      templateUrl: './app.component.html',
      styleUrls: ['./app.component.css']
    })
    export class AppComponent implements OnInit, OnDestroy {
      title = 'msal-angular-tutorial';
      isIframe = false;
      loginDisplay = false;
      private readonly _destroying$ = new Subject<void>();
    
      constructor(private broadcastService: MsalBroadcastService, private authService: MsalService) { }
    
      ngOnInit() {
        this.isIframe = window !== window.parent && !window.opener;
    
        this.broadcastService.inProgress$
        .pipe(
          filter((status: InteractionStatus) => status === InteractionStatus.None),
          takeUntil(this._destroying$)
        )
        .subscribe(() => {
          this.setLoginDisplay();
        })
      }
    
      login() {
        this.authService.loginRedirect();
      }
    
      setLoginDisplay() {
        this.loginDisplay = this.authService.instance.getAllAccounts().length > 0;
      }
    
      ngOnDestroy(): void {
        this._destroying$.next(undefined);
        this._destroying$.complete();
      }
    }
    
  2. Kullanıcı arabirimini güncelleştirmeden önce etkileşimin tamamlanacağını denetlemek için src/app/home/home.component.ts içindeki kodu güncelleştirin. Kodunuz şimdi şöyle görünmelidir:

    import { Component, OnInit } from '@angular/core';
    import { MsalBroadcastService, MsalService } from '@azure/msal-angular';
    import { EventMessage, EventType, InteractionStatus } from '@azure/msal-browser';
    import { filter } from 'rxjs/operators';
    
    @Component({
      selector: 'app-home',
      templateUrl: './home.component.html',
      styleUrls: ['./home.component.css']
    })
    export class HomeComponent implements OnInit {
      loginDisplay = false;
    
      constructor(private authService: MsalService, private msalBroadcastService: MsalBroadcastService) { }
    
      ngOnInit(): void {
        this.msalBroadcastService.msalSubject$
          .pipe(
            filter((msg: EventMessage) => msg.eventType === EventType.LOGIN_SUCCESS),
          )
          .subscribe((result: EventMessage) => {
            console.log(result);
          });
    
        this.msalBroadcastService.inProgress$
          .pipe(
            filter((status: InteractionStatus) => status === InteractionStatus.None)
          )
          .subscribe(() => {
            this.setLoginDisplay();
          })
      }
    
      setLoginDisplay() {
        this.loginDisplay = this.authService.instance.getAllAccounts().length > 0;
      }
    }
    
  3. src/app/home/home.component.html içindeki kodu aşağıdaki koşullu görüntülerle değiştirin:

    <div *ngIf="!loginDisplay">
        <p>Please sign-in to see your profile information.</p>
    </div>
    
    <div *ngIf="loginDisplay">
        <p>Login successful!</p>
        <p>Request your profile information by clicking Profile above.</p>
    </div>
    

Angular Guard Uygulama

sınıfı MsalGuard , korumalı yola erişmeden önce yolları korumak ve kimlik doğrulaması gerektirmek için kullanabileceğiniz sınıftır. Aşağıdaki adımlar yolunu MsalGuardProfile ekler. Yolu korumak Profile , bir kullanıcı düğmeyi Login kullanarak oturum açmasa bile, yola erişmeye Profile veya düğmeyi seçmeye Profile çalışırsa, MsalGuard sayfayı göstermeden önce kullanıcıdan açılır pencere veya yeniden yönlendirme yoluyla kimlik doğrulaması istemesi Profile anlamına gelir.

MsalGuard , kullanıcı deneyimini geliştirmek için kullanabileceğiniz bir kolaylık sınıfıdır, ancak güvenlik için bu sınıfa güvenilmemelidir. Saldırganlar potansiyel olarak istemci tarafı korumalarını kullanabilir ve sunucunun kullanıcının erişmemesi gereken verileri döndürmediğinden emin olmanız gerekir.

  1. MsalGuard src/app/app.module.ts içinde sınıfını uygulamanıza sağlayıcı olarak ekleyin ve için MsalGuardyapılandırmaları ekleyin. Belirteçleri daha sonra almak için gereken kapsamlar içinde authRequestsağlanabilir ve Guard'ın etkileşim türü veya Popupolarak Redirect ayarlanabilir. Kodunuz aşağıdaki gibi görünmelidir:

    import { BrowserModule } from "@angular/platform-browser";
    import { BrowserAnimationsModule } from "@angular/platform-browser/animations";
    import { NgModule } from "@angular/core";
    
    import { MatButtonModule } from "@angular/material/button";
    import { MatToolbarModule } from "@angular/material/toolbar";
    import { MatListModule } from "@angular/material/list";
    
    import { AppRoutingModule } from "./app-routing.module";
    import { AppComponent } from "./app.component";
    import { HomeComponent } from "./home/home.component";
    import { ProfileComponent } from "./profile/profile.component";
    
    import {
      MsalModule,
      MsalRedirectComponent,
      MsalGuard,
    } from "@azure/msal-angular"; // MsalGuard added to imports
    import {
      PublicClientApplication,
      InteractionType,
    } from "@azure/msal-browser"; // InteractionType added to imports
    
    const isIE =
      window.navigator.userAgent.indexOf("MSIE ") > -1 ||
      window.navigator.userAgent.indexOf("Trident/") > -1;
    
    @NgModule({
      declarations: [AppComponent, HomeComponent, ProfileComponent],
      imports: [
        BrowserModule,
        BrowserAnimationsModule,
        AppRoutingModule,
        MatButtonModule,
        MatToolbarModule,
        MatListModule,
        MsalModule.forRoot(
          new PublicClientApplication({
            auth: {
              clientId: "Enter_the_Application_Id_here",
              authority:
                "Enter_the_Cloud_Instance_Id_Here/Enter_the_Tenant_Info_Here",
              redirectUri: "Enter_the_Redirect_Uri_Here",
            },
            cache: {
              cacheLocation: "localStorage",
              storeAuthStateInCookie: isIE,
            },
          }),
          {
            interactionType: InteractionType.Redirect, // MSAL Guard Configuration
            authRequest: {
              scopes: ["user.read"],
            },
          },
          null
        ),
      ],
      providers: [
        MsalGuard, // MsalGuard added as provider here
      ],
      bootstrap: [AppComponent, MsalRedirectComponent],
    })
    export class AppModule {}
    
  2. MsalGuard src/app/app-routing.module.ts içinde korumak istediğiniz yolları ayarlayın:

    import { NgModule } from "@angular/core";
    import { Routes, RouterModule } from "@angular/router";
    import { BrowserUtils } from "@azure/msal-browser";
    import { HomeComponent } from "./home/home.component";
    import { ProfileComponent } from "./profile/profile.component";
    import { MsalGuard } from "@azure/msal-angular";
    
    const routes: Routes = [
      {
        path: "profile",
        component: ProfileComponent,
        canActivate: [MsalGuard],
      },
      {
        path: "",
        component: HomeComponent,
      },
    ];
    
    const isIframe = window !== window.parent && !window.opener;
    
    @NgModule({
      imports: [
        RouterModule.forRoot(routes, {
          // Don't perform initial navigation in iframes or popups
          initialNavigation:
            !BrowserUtils.isInIframe() && !BrowserUtils.isInPopup()
              ? "enabledNonBlocking"
              : "disabled", // Set to enabledBlocking to use Angular Universal
        }),
      ],
      exports: [RouterModule],
    })
    export class AppRoutingModule {}
    
  3. src/app/app.component.ts oturum açma çağrılarını, koruma yapılandırmalarındaki kümeyi authRequest hesaba katacak şekilde ayarlayın. Kodunuz şimdi aşağıdaki gibi görünmelidir:

    import { Component, OnInit, OnDestroy, Inject } from '@angular/core';
    import { MsalService, MsalBroadcastService, MSAL_GUARD_CONFIG, MsalGuardConfiguration } from '@azure/msal-angular';
    import { InteractionStatus, RedirectRequest } from '@azure/msal-browser';
    import { Subject } from 'rxjs';
    import { filter, takeUntil } from 'rxjs/operators';
    
    @Component({
      selector: 'app-root',
      templateUrl: './app.component.html',
      styleUrls: ['./app.component.css']
    })
    export class AppComponent implements OnInit, OnDestroy {
      title = 'msal-angular-tutorial';
      isIframe = false;
      loginDisplay = false;
      private readonly _destroying$ = new Subject<void>();
    
      constructor(@Inject(MSAL_GUARD_CONFIG) private msalGuardConfig: MsalGuardConfiguration, private broadcastService: MsalBroadcastService, private authService: MsalService) { }
    
      ngOnInit() {
        this.isIframe = window !== window.parent && !window.opener;
    
        this.broadcastService.inProgress$
        .pipe(
          filter((status: InteractionStatus) => status === InteractionStatus.None),
          takeUntil(this._destroying$)
        )
        .subscribe(() => {
          this.setLoginDisplay();
        })
      }
    
      login() {
        if (this.msalGuardConfig.authRequest){
          this.authService.loginRedirect({...this.msalGuardConfig.authRequest} as RedirectRequest);
        } else {
          this.authService.loginRedirect();
        }
      }
    
      setLoginDisplay() {
        this.loginDisplay = this.authService.instance.getAllAccounts().length > 0;
      }
    
      ngOnDestroy(): void {
        this._destroying$.next(undefined);
        this._destroying$.complete();
      }
    }
    

Belirteç alma

Angular Kesme Noktası

MSAL Angular, Angular http istemcisini kullanan giden istekler için belirteçleri bilinen korumalı kaynaklara otomatik olarak alan bir Interceptor sınıf sağlar.

  1. Interceptor src/app/app.module.ts'da sınıfını yapılandırmalarıyla uygulamanıza sağlayıcı olarak ekleyin. Kodunuz şimdi aşağıdaki gibi görünmelidir:

    import { BrowserModule } from "@angular/platform-browser";
    import { BrowserAnimationsModule } from "@angular/platform-browser/animations";
    import { NgModule } from "@angular/core";
    import { HTTP_INTERCEPTORS, HttpClientModule } from "@angular/common/http"; // Import
    
    import { MatButtonModule } from "@angular/material/button";
    import { MatToolbarModule } from "@angular/material/toolbar";
    import { MatListModule } from "@angular/material/list";
    
    import { AppRoutingModule } from "./app-routing.module";
    import { AppComponent } from "./app.component";
    import { HomeComponent } from "./home/home.component";
    import { ProfileComponent } from "./profile/profile.component";
    
    import {
      MsalModule,
      MsalRedirectComponent,
      MsalGuard,
      MsalInterceptor,
    } from "@azure/msal-angular"; // Import MsalInterceptor
    import {
      InteractionType,
      PublicClientApplication,
    } from "@azure/msal-browser";
    
    const isIE =
      window.navigator.userAgent.indexOf("MSIE ") > -1 ||
      window.navigator.userAgent.indexOf("Trident/") > -1;
    
    @NgModule({
      declarations: [AppComponent, HomeComponent, ProfileComponent],
      imports: [
        BrowserModule,
        BrowserAnimationsModule,
        AppRoutingModule,
        MatButtonModule,
        MatToolbarModule,
        MatListModule,
        HttpClientModule,
        MsalModule.forRoot(
          new PublicClientApplication({
            auth: {
              clientId: "Enter_the_Application_Id_Here",
              authority:
                "Enter_the_Cloud_Instance_Id_Here/Enter_the_Tenant_Info_Here",
              redirectUri: "Enter_the_Redirect_Uri_Here",
            },
            cache: {
              cacheLocation: "localStorage",
              storeAuthStateInCookie: isIE,
            },
          }),
          {
            interactionType: InteractionType.Redirect,
            authRequest: {
              scopes: ["user.read"],
            },
          },
          {
            interactionType: InteractionType.Redirect, // MSAL Interceptor Configuration
            protectedResourceMap: new Map([
              ["Enter_the_Graph_Endpoint_Here/v1.0/me", ["user.read"]],
            ]),
          }
        ),
      ],
      providers: [
        {
          provide: HTTP_INTERCEPTORS,
          useClass: MsalInterceptor,
          multi: true,
        },
        MsalGuard,
      ],
      bootstrap: [AppComponent, MsalRedirectComponent],
    })
    export class AppModule {}
    

    Korumalı kaynaklar olarak protectedResourceMapsağlanır. Koleksiyonda protectedResourceMap sağladığınız URL'ler büyük/küçük harfe duyarlıdır. Her kaynak için erişim belirtecinde döndürülmesini istenen kapsamları ekleyin.

    Örneğin:

    • ["user.read"] Microsoft Graph için
    • ["<Application ID URL>/scope"]özel web API'leri için (yani ) api://<Application ID>/access_as_user

    içindeki protectedResourceMap değerleri burada açıklandığı gibi değiştirin:

  2. Kullanıcının profilini HTTP isteğiyle almak için src/app/profile/profile.component.ts içindeki kodu değiştirin ve değerini Microsoft Graph uç noktasıyla değiştirinGRAPH_ENDPOINT:

    import { Component, OnInit } from '@angular/core';
    import { HttpClient } from '@angular/common/http';
    
    const GRAPH_ENDPOINT = 'Enter_the_Graph_Endpoint_Here/v1.0/me';
    
    type ProfileType = {
      givenName?: string,
      surname?: string,
      userPrincipalName?: string,
      id?: string
    };
    
    @Component({
      selector: 'app-profile',
      templateUrl: './profile.component.html',
      styleUrls: ['./profile.component.css']
    })
    export class ProfileComponent implements OnInit {
      profile!: ProfileType;
    
      constructor(
        private http: HttpClient
      ) { }
    
      ngOnInit() {
        this.getProfile();
      }
    
      getProfile() {
        this.http.get(GRAPH_ENDPOINT)
          .subscribe(profile => {
            this.profile = profile;
          });
      }
    }
    
  3. profil bilgilerini görüntülemek için src/app/profile/profile.component.html kullanıcı arabirimini değiştirin:

    <div>
        <p><strong>First Name: </strong> {{profile?.givenName}}</p>
        <p><strong>Last Name: </strong> {{profile?.surname}}</p>
        <p><strong>Email: </strong> {{profile?.userPrincipalName}}</p>
        <p><strong>Id: </strong> {{profile?.id}}</p>
    </div>
    

Oturumu kapat

  1. bir düğmeyi koşullu olarak görüntülemek Logout için src/app/app.component.html kodunu güncelleştirin:

    <mat-toolbar color="primary">
      <a class="title" href="/">{{ title }}</a>
    
      <div class="toolbar-spacer"></div>
    
      <a mat-button [routerLink]="['profile']">Profile</a>
    
      <button mat-raised-button *ngIf="!loginDisplay" (click)="login()">Login</button>
      <button mat-raised-button *ngIf="loginDisplay" (click)="logout()">Logout</button>
    
    </mat-toolbar>
    <div class="container">
      <!--This is to avoid reload during acquireTokenSilent() because of hidden iframe -->
      <router-outlet *ngIf="!isIframe"></router-outlet>
    </div>
    

Yeniden yönlendirmeleri kullanarak oturumu kapatma

  1. Yeniden yönlendirmeleri kullanarak kullanıcının oturumunu kapatmak için src/app/app.component.ts içindeki kodu güncelleştirin:

    import { Component, OnInit, OnDestroy, Inject } from '@angular/core';
    import { MsalService, MsalBroadcastService, MSAL_GUARD_CONFIG, MsalGuardConfiguration } from '@azure/msal-angular';
    import { InteractionStatus, RedirectRequest } from '@azure/msal-browser';
    import { Subject } from 'rxjs';
    import { filter, takeUntil } from 'rxjs/operators';
    
    @Component({
      selector: 'app-root',
      templateUrl: './app.component.html',
      styleUrls: ['./app.component.css']
    })
    export class AppComponent implements OnInit, OnDestroy {
      title = 'msal-angular-tutorial';
      isIframe = false;
      loginDisplay = false;
      private readonly _destroying$ = new Subject<void>();
    
      constructor(@Inject(MSAL_GUARD_CONFIG) private msalGuardConfig: MsalGuardConfiguration, private broadcastService: MsalBroadcastService, private authService: MsalService) { }
    
      ngOnInit() {
        this.isIframe = window !== window.parent && !window.opener;
    
        this.broadcastService.inProgress$
        .pipe(
          filter((status: InteractionStatus) => status === InteractionStatus.None),
          takeUntil(this._destroying$)
        )
        .subscribe(() => {
          this.setLoginDisplay();
        })
      }
    
      login() {
        if (this.msalGuardConfig.authRequest){
          this.authService.loginRedirect({...this.msalGuardConfig.authRequest} as RedirectRequest);
        } else {
          this.authService.loginRedirect();
        }
      }
    
      logout() { // Add log out function here
        this.authService.logoutRedirect({
          postLogoutRedirectUri: 'http://localhost:4200'
        });
      }
    
      setLoginDisplay() {
        this.loginDisplay = this.authService.instance.getAllAccounts().length > 0;
      }
    
      ngOnDestroy(): void {
        this._destroying$.next(undefined);
        this._destroying$.complete();
      }
    }
    

Açılır pencereleri kullanarak oturumu kapatma

  1. Src/app/app.component.ts içindeki kodu, açılır pencereleri kullanarak bir kullanıcının oturumunu kapatmak için güncelleştirin:

    import { Component, OnInit, OnDestroy, Inject } from '@angular/core';
    import { MsalService, MsalBroadcastService, MSAL_GUARD_CONFIG, MsalGuardConfiguration } from '@azure/msal-angular';
    import { InteractionStatus, PopupRequest } from '@azure/msal-browser';
    import { Subject } from 'rxjs';
    import { filter, takeUntil } from 'rxjs/operators';
    
    @Component({
      selector: 'app-root',
      templateUrl: './app.component.html',
      styleUrls: ['./app.component.css']
    })
    export class AppComponent implements OnInit, OnDestroy {
      title = 'msal-angular-tutorial';
      isIframe = false;
      loginDisplay = false;
      private readonly _destroying$ = new Subject<void>();
    
      constructor(@Inject(MSAL_GUARD_CONFIG) private msalGuardConfig: MsalGuardConfiguration, private broadcastService: MsalBroadcastService, private authService: MsalService) { }
    
      ngOnInit() {
        this.isIframe = window !== window.parent && !window.opener;
    
        this.broadcastService.inProgress$
        .pipe(
          filter((status: InteractionStatus) => status === InteractionStatus.None),
          takeUntil(this._destroying$)
        )
        .subscribe(() => {
          this.setLoginDisplay();
        })
      }
    
      login() {
        if (this.msalGuardConfig.authRequest){
          this.authService.loginPopup({...this.msalGuardConfig.authRequest} as PopupRequest)
            .subscribe({
              next: (result) => {
                console.log(result);
                this.setLoginDisplay();
              },
              error: (error) => console.log(error)
            });
        } else {
          this.authService.loginPopup()
            .subscribe({
              next: (result) => {
                console.log(result);
                this.setLoginDisplay();
              },
              error: (error) => console.log(error)
            });
        }
      }
    
      logout() { // Add log out function here
        this.authService.logoutPopup({
          mainWindowRedirectUri: "/"
        });
      }
    
      setLoginDisplay() {
        this.loginDisplay = this.authService.instance.getAllAccounts().length > 0;
      }
    
      ngOnDestroy(): void {
        this._destroying$.next(undefined);
        this._destroying$.complete();
      }
    }
    

Kodunuza test etme

  1. Uygulama klasöründen bir komut satırı isteminde aşağıdaki komutları çalıştırarak bağlantı noktasını dinlemek için web sunucusunu başlatın:

    npm install
    npm start
    
  2. Tarayıcınızda yazın http://localhost:4200ve aşağıdakine benzer bir sayfa görmeniz gerekir.

    Oturum açma iletişim kutusunu görüntüleyen web tarayıcısı

  3. Profilinize uygulama izinleri vermek için Kabul Et'i seçin. Bu, ilk kez oturum açmaya başladığınızda gerçekleşir.

    Web tarayıcısında görüntülenen içerik iletişim kutusu

  4. Onay verdikten sonra, aşağıdaki İstenen izinleri onaylarsanız web uygulaması başarılı bir oturum açma sayfası gösterir.

    Web tarayıcısında başarılı bir oturum açma işleminin sonuçları

  5. Microsoft Graph API'sine yapılan çağrıdan yanıtta döndürülen kullanıcı profili bilgilerini görüntülemek için Profil'i seçin:

    Tarayıcıda görüntülenen Microsoft Graph profil bilgileri

Kapsamlar ve temsilci izinleri ekleme

Microsoft Graph API'sinde bir kullanıcının profilini okumak için User.Read kapsamı gerekir. User.Read kapsamı her uygulama kaydına otomatik olarak eklenir. Microsoft Graph için diğer API'ler ve arka uç sunucunuz için özel API'ler başka kapsamlar gerektirebilir. Örneğin, Microsoft Graph API'sinde kullanıcının e-postasını listelemek için Mail.Read kapsamı gerekir.

Kapsam eklediğinizde, kullanıcılarınızdan eklenen kapsamlar için ek onay vermesi istenebilir.

Not

Kapsam sayısını artırdığınızda kullanıcıdan ek onaylar istenebilir.

Yardım ve destek 

Yardıma ihtiyacınız varsa, bir sorunu bildirmek veya destek seçenekleriniz hakkında bilgi edinmek istiyorsanız bkz . Geliştiriciler için yardım ve destek.

Sonraki adımlar

  • Aşağıdaki çok bölümlü öğretici serisinde kullanıcılara oturum açmanızı sağlayan bir React Tek sayfalı uygulama (SPA) oluşturarak daha fazla bilgi edinin.