다음을 통해 공유


자습서: Angular SPA에서 인증 흐름 처리

이 자습서는 Angular SPA(단일 페이지 앱)를 빌드하고 인증을 준비하는 방법을 보여 주는 시리즈의 3부입니다. 이 시리즈의 2부에서는 외부 테넌트와의 인증을 위해 Angular SPA를 만들고 준비했습니다. 이 자습서에서는 MSAL(Microsoft 인증 라이브러리) 구성 요소를 추가하여 앱에서 인증 흐름을 처리하는 방법을 알아봅니다.

이 자습서에서는 다음을 수행합니다.

  • 애플리케이션에 인증 흐름 추가
  • MSAL 구성 요소 가져오기
  • 애플리케이션의 홈 및 보호된 구성 요소에 대한 경로를 추가합니다.

필수 조건

인증 구성 파일 auth-config.ts 만들기

  1. src/app/ 폴더에 auth-config.ts라는 새 파일을 만들고 다음 코드 조각을 추가합니다. 이 파일에는 인증 매개 변수가 포함되어 있습니다. 이러한 매개 변수는 Angular 및 MSAL Angular 구성을 초기화하는 데 사용됩니다.

    
    /**
     * This file contains authentication parameters. Contents of this file
     * is roughly the same across other MSAL.js libraries. These parameters
     * are used to initialize Angular and MSAL Angular configurations in
     * in app.module.ts file.
     */
    
    import {
      LogLevel,
      Configuration,
      BrowserCacheLocation,
    } from '@azure/msal-browser';
    
    /**
     * Configuration object to be passed to MSAL instance on creation.
     * For a full list of MSAL.js configuration parameters, visit:
     * https://github.com/AzureAD/microsoft-authentication-library-for-js/blob/dev/lib/msal-browser/docs/configuration.md
     */
    export const msalConfig: Configuration = {
      auth: {
        clientId: 'Enter_the_Application_Id_Here', // This is the ONLY mandatory field that you need to supply.
        authority: 'https://Enter_the_Tenant_Subdomain_Here.ciamlogin.com/', // Replace the placeholder with your tenant subdomain
        redirectUri: '/', // Points to window.location.origin by default. You must register this URI on Azure portal/App Registration.
        postLogoutRedirectUri: '/', // Points to window.location.origin by default.
      },
      cache: {
        cacheLocation: BrowserCacheLocation.LocalStorage, // Configures cache location. "sessionStorage" is more secure, but "localStorage" gives you SSO between tabs.
      },
      system: {
        loggerOptions: {
          loggerCallback(logLevel: LogLevel, message: string) {
            console.log(message);
          },
          logLevel: LogLevel.Verbose,
          piiLoggingEnabled: false,
        },
      },
    };
    
    /**
     * Scopes you add here will be prompted for user consent during sign-in.
     * By default, MSAL.js will add OIDC scopes (openid, profile, email) to any login request.
     * For more information about OIDC scopes, visit:
     * https://learn.microsoft.com/entra/identity-platform/permissions-consent-overview#openid-connect-scopes
     */
    export const loginRequest = {
      scopes: [],
    };
    
  2. 다음 값을 Microsoft Entra 관리 센터의 값으로 바꿉니다.

    • Enter_the_Application_Id_Here 값을 찾아 Microsoft Entra 관리 센터에 등록한 앱의 애플리케이션 ID(clientId)로 바꿉니다.
    • 권한에서 Enter_the_Tenant_Subdomain_Here를 찾아 테넌트의 하위 도메인으로 바꿉니다. 예를 들어, 테넌트 기본 도메인이 contoso.onmicrosoft.com인 경우 contoso를 사용합니다. 테넌트 이름이 없는 경우 테넌트 세부 정보를 읽는 방법을 알아봅니다.
  3. 파일을 저장합니다.

사용자 지정 URL 도메인 사용(선택 사항)

사용자 지정 도메인을 사용하여 인증 URL을 완전히 브랜딩합니다. 사용자 관점에서 볼 때, 사용자는 인증 과정 동안 ciamlogin.com 도메인 이름으로 리디렉션되는 것이 아니라 도메인에 남아 있습니다.

사용자 지정 도메인을 사용하려면 다음 단계를 따릅니다.

  1. 외부 테넌트에 대한 사용자 지정 URL 도메인을 사용하도록 설정하려면 외부 테넌트의 앱에 대한 사용자 지정 URL 도메인 사용의 단계를 사용합니다.

  2. authConfig.js 파일에서 auth 개체를 찾은 후 다음을 수행합니다.

    1. authority 속성의 값을 https://Enter_the_Custom_Domain_Here/Enter_the_Tenant_ID_Here로 업데이트합니다. Enter_the_Custom_Domain_Here를 사용자 지정 URL 도메인으로, Enter_the_Tenant_ID_Here를 테넌트 ID로 바꿉니다. 테넌트 ID가 없는 경우 테넌트 세부 정보를 읽는 방법을 알아봅니다.
    2. [Enter_the_Custom_Domain_Here] 값을 갖는 knownAuthorities 속성을 추가합니다.

authConfig.js 파일을 변경한 후 사용자 지정 URL 도메인이 login.contoso.com이고 테넌트 ID가 aaaabbbb-0000-cccc-1111-dddd2222eeee인 경우 파일은 다음 코드 조각과 유사해야 합니다.

//...
const msalConfig = {
    auth: {
        authority: process.env.AUTHORITY || 'https://login.contoso.com/aaaabbbb-0000-cccc-1111-dddd2222eeee', 
        knownAuthorities: ["login.contoso.com"],
        //Other properties
    },
    //...
};

MSAL 구성 요소 가져오기

  1. src/app/app.module.ts를 열고 다음 코드 조각을 추가합니다.

    import { NgModule } from '@angular/core';
    import { BrowserModule } from '@angular/platform-browser';
    import { HTTP_INTERCEPTORS, HttpClientModule } from '@angular/common/http';
    
    import { MatToolbarModule } from "@angular/material/toolbar";
    import { MatButtonModule } from '@angular/material/button';
    import { MatCardModule } from '@angular/material/card';
    import { MatTableModule } from '@angular/material/table';
    import { MatMenuModule } from '@angular/material/menu';
    import { MatDialogModule } from '@angular/material/dialog';
    import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
    import { MatIconModule } from '@angular/material/icon';
    
    import { AppRoutingModule } from './app-routing.module';
    import { AppComponent } from './app.component';
    import { HomeComponent } from './home/home.component';
    import { GuardedComponent } from './guarded/guarded.component';
    
    import {
        IPublicClientApplication,
        PublicClientApplication,
        InteractionType,
    } from '@azure/msal-browser';
    
    import {
        MSAL_INSTANCE,
        MsalGuardConfiguration,
        MSAL_GUARD_CONFIG,
        MsalService,
        MsalBroadcastService,
        MsalGuard,
        MsalRedirectComponent,
        MsalInterceptor,
        MsalModule,
    } from '@azure/msal-angular';
    
    import { msalConfig, loginRequest } from './auth-config';
    
    /**
     * Here we pass the configuration parameters to create an MSAL instance.
        * For more info, visit: https://github.com/AzureAD/microsoft-authentication-library-for-js/blob/dev/lib/msal-angular/docs/v2-docs/configuration.md
        */
    export function MSALInstanceFactory(): IPublicClientApplication {
        return new PublicClientApplication(msalConfig);
    }
    
    /**
     * Set your default interaction type for MSALGuard here. If you have any
        * additional scopes you want the user to consent upon login, add them here as well.
        */
    export function MsalGuardConfigurationFactory(): MsalGuardConfiguration {
        return {
        interactionType: InteractionType.Redirect,
        authRequest: loginRequest
        };
    }
    
    @NgModule({
        declarations: [
        AppComponent,
        HomeComponent,
        GuardedComponent,
        ],
        imports: [
        BrowserModule,
        BrowserAnimationsModule,
        AppRoutingModule,
        MatToolbarModule,
        MatButtonModule,
        MatCardModule,
        MatTableModule,
        MatMenuModule,
        HttpClientModule,
        BrowserAnimationsModule,
        MatDialogModule,
        MatIconModule,
        MsalModule,
        ],
        providers: [
        {
            provide: HTTP_INTERCEPTORS,
            useClass: MsalInterceptor,
            multi: true,
        },
        {
            provide: MSAL_INSTANCE,
            useFactory: MSALInstanceFactory,
        },
        {
            provide: MSAL_GUARD_CONFIG,
            useFactory: MsalGuardConfigurationFactory,
        },
        MsalService,
        MsalBroadcastService,
        MsalGuard,
        ],
        bootstrap: [AppComponent, MsalRedirectComponent],
    })
    export class AppModule { }
    
  2. src/app/app-routing.module.ts를 열고 파일의 전체 콘텐츠를 다음 코드 조각으로 바꿉니다. 그러면 경로에 homeguarded 구성 요소가 추가됩니다.

    import { NgModule } from '@angular/core';
    import { RouterModule, Routes } from '@angular/router';
    import { BrowserUtils } from '@azure/msal-browser';
    import { MsalGuard } from '@azure/msal-angular';
    
    import { HomeComponent } from './home/home.component';
    import { GuardedComponent } from './guarded/guarded.component';
    
    /**
     * MSAL Angular can protect routes in your application
        * using MsalGuard. For more info, visit:
        * https://github.com/AzureAD/microsoft-authentication-library-for-js/blob/dev/lib/msal-angular/docs/v2-docs/initialization.md#secure-the-routes-in-your-application
        */
    const routes: Routes = [
        {
        path: 'guarded',
        component: GuardedComponent,
        canActivate: [
            MsalGuard
        ]
        },
        {
        path: '',
        component: HomeComponent,
        },
    ];
    
    @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 { }
    

다음 단계