Självstudie: Aktivera multifaktorautentisering i en enkelsidig Angular-app med inbyggd autentisering med JavaScript SDK

Gäller för: Grön cirkel med en vit bockmarkeringssymbol som anger att följande innehåll gäller för externa klienter. Externa klienter (läs mer)

I den här självstudien får du lära dig hur du lägger till multifaktorautentisering (MFA) i ditt Angular-ensidesprogram (SPA) med hjälp av den interna autentiseringens JavaScript SDK.

Precis som vid stark registrering av autentiseringsmetoder sker MFA-flödet i tre scenarier:

  • Under inloggningen: Användaren loggar in och har en stark autentiseringsmetod registrerad.
  • Efter registreringen: När användaren har slutfört registreringen fortsätter de att logga in. Nya användare måste registrera en stark autentiseringsmetod innan någon MFA-utmaning. Eftersom den starka autentiseringsmetoden också verifieras under registreringen kanske de inte uppmanas till ytterligare en MFA-utmaning.
  • Efter självbetjänad lösenordsåterställning (SSPR): Användaren återställer sitt lösenord och loggar in automatiskt. Om användaren har en stark autentiseringsmetod registrerad uppmanas de att slutföra MFA-utmaningen.

När MFA krävs väljer användaren en MFA-utmaningsmetod från en lista över registrerade metoder. Tillgängliga alternativ är engångslösenord för e-post , SMS engångslösenord eller båda, beroende på vad användaren registrerade tidigare.

Flödesdiagrammet nedan illustrerar de tre scenarierna:

Slutför multifaktorautentiseringsutmaningen.

Förutsättningar

Aktivera app för att hantera multifaktorautentisering

Om du vill aktivera MFA i din Angular-app uppdaterar du appkonfigurationen genom att lägga till den nödvändiga funktionen:

  1. Leta upp filen src/app/config/auth-config.ts .

  2. customAuth I -objektet lägger du till eller uppdaterar capabilities egenskapen för att inkludera mfa_required värdet i matrisen enligt följande kodfragment:

    const customAuthConfig: CustomAuthConfiguration = {
        customAuth: {
            ...
            capabilities: ["mfa_required"],
            ...
        },
        ...
    };
    

Funktionsvärdet mfa_required informerar Microsoft Entra om att din app kan hantera ett MFA-flöde. Läs mer om inbyggda autentiseringsutmaningstyper och funktioner.

Skapa gränssnittskomponenter

Du behöver formulärkomponenter i din app för att stödja MFA-flödet, till exempel för att välja MFA-utmaningsmetod och skicka MFA-utmaning.

Skapa markeringsformulär för multifaktorautentiseringsmetod

  1. I konsolen går du till mappen src/app/components/shared och använder sedan Angular CLI för att skapa en komponent som mfa-auth-method-selection-form med hjälp av följande kommando:

    ng generate component mfa-auth-method-selection-form
    

    Det här kommandot genererar mfa-auth-method-selection-form.component.html och mfa-auth-method-selection-form.component.ts filer i mappen src/app/components/shared/mfa-auth-method-selection-form/.

  2. Öppna filen mfa-auth-method-selection-form.component.ts och ersätt innehållet med innehållet i mfa-auth-method-selection-form.component.ts.

  3. Öppna filen mfa-auth-method-selection-form.component.html och lägg sedan till innehållet i mfa-auth-method-selection-form.component.html.

Skapa utmaningsformulär för multifaktorautentisering

  1. I konsolen går du till mappen src/app/components/shared och använder sedan Angular CLI för att skapa en komponent som mfa-challenge-form med hjälp av följande kommando:

    ng generate component mfa-challenge-form
    

    Det här kommandot genererar mfa-challenge-form.component.ts och mfa-challenge-form.component.html filer i mappen src/app/components/shared/mfa-challenge-form/.

  2. Öppna filen mfa-challenge-form.component.ts och ersätt innehållet med innehållet i mfa-challenge-form.component.ts.

  3. Öppna filen mfa-challenge-form.component.html och lägg sedan till innehållet i mfa-challenge-form.component.html.

Hantera multifaktorautentisering vid inloggning

Uppdatera filen src/app/components/sign-in/sign-in.component.ts så att appen kan hantera MFA-flödet under inloggningen. Se den fullständiga koden i sign-in.component.ts:

  1. Importera de nödvändiga typerna och komponenterna enligt följande kodfragment:

    import {
        AuthenticationMethod,
        MfaAwaitingState,
        MfaVerificationRequiredState,
    } from "@azure/msal-browser/custom-auth";
    import { MfaAuthMethodSelectionFormComponent } from "../shared/mfa-auth-method-selection-form/mfa-auth-method-selection-form.component";
    import { MfaChallengeFormComponent } from "../shared/mfa-challenge-form/mfa-challenge-form.component";
    
    @Component({
        selector: "app-sign-in",
        templateUrl: "./sign-in.component.html",
        standalone: true,
        imports: [
            ...
            MfaAuthMethodSelectionFormComponent,
            MfaChallengeFormComponent,
            ...
        ],
    })
    
  2. Lägg till nya tillståndsvariabler för MFA:

    export default function SignIn() {
        ...
        // MFA states
    const [mfaAuthMethods, setMfaAuthMethods] = useState<AuthenticationMethod[]>([]);
    const [selectedMfaAuthMethod, setSelectedMfaAuthMethod] = useState<AuthenticationMethod | undefined>(undefined);
    const [mfaChallenge, setMfaChallenge] = useState("");
    
        // ... initialization code
    }
    
  3. Uppdatera startSignIn, handlePasswordSubmit och handleCodeSubmit funktionerna för att kontrollera om MFA krävs:

    async startSignIn() {
        const client = await this.auth.getClient();
        const result: SignInResult = await client.signIn({ username: this.username });
    
        ...
    
        if (result.isMfaRequired()) {
            this.showMfaAuthMethods = true;
            this.showPassword = false;
            this.showCode = false;
            this.showAuthMethodsForRegistration = false;
            this.showChallengeForRegistration = false;
            this.showMfaChallenge = false;
            this.mfaAuthMethods = result.state.getAuthMethods();
            // Set default selection to the first MFA auth method
            this.selectedMfaAuthMethod = this.mfaAuthMethods.length > 0 ? this.mfaAuthMethods[0] : undefined;
            this.signInState = result.state;
        }
    
        ...
    }
    
    async submitPassword() {
        if (this.signInState instanceof SignInPasswordRequiredState) {
            const result = await this.signInState.submitPassword(this.password);
    
            ...
    
            if (result.isMfaRequired()) {
                this.showMfaAuthMethods = true;
                this.showPassword = false;
                this.showCode = false;
                this.showAuthMethodsForRegistration = false;
                this.showChallengeForRegistration = false;
                this.showMfaChallenge = false;
                this.mfaAuthMethods = result.state.getAuthMethods();
                // Set default selection to the first MFA auth method
                this.selectedMfaAuthMethod = this.mfaAuthMethods.length > 0 ? this.mfaAuthMethods[0] : undefined;
                this.signInState = result.state;
            }
    
            ...
        }
    }
    
    async submitCode() {
        if (this.signInState instanceof SignInCodeRequiredState) {
            const result = await this.signInState.submitCode(this.code);
    
            ...
    
            if (result.isMfaRequired()) {
                this.showMfaAuthMethods = true;
                this.showPassword = false;
                this.showCode = false;
                this.showAuthMethodsForRegistration = false;
                this.showChallengeForRegistration = false;
                this.showMfaChallenge = false;
                this.mfaAuthMethods = result.state.getAuthMethods();
                // Set default selection to the first MFA auth method
                this.selectedMfaAuthMethod = this.mfaAuthMethods.length > 0 ? this.mfaAuthMethods[0] : undefined;
                this.signInState = result.state;
            }
        }
    }
    

    Observera att vi i var och en av funktionerna kontrollerar om MFA krävs med hjälp av följande kodfragment:

    if (result.isMfaRequired()) {...}
    
  4. Lägg till hanteraren för MFA-utmaningsval:

    async submitMfaAuthMethod() {
        this.error = "";
        this.loading = true;
    
        if (!this.selectedMfaAuthMethod) {
            this.error = "Please select an authentication method.";
            this.loading = false;
            return;
        }
    
        if (this.signInState instanceof MfaAwaitingState) {
            const result = await this.signInState.requestChallenge(this.selectedMfaAuthMethod.id);
    
            if (result.isFailed()) {
                if (result.error?.isInvalidInput()) {
                    this.error = "Incorrect verification contact.";
                } else {
                    this.error =
                        result.error?.errorData?.errorDescription ||
                        "An error occurred while verifying the authentication method.";
                }
            }
    
            if (result.isVerificationRequired()) {
                this.showMfaAuthMethods = false;
                this.showMfaChallenge = true;
                this.signInState = result.state;
            }
        }
        this.loading = false;
    }
    
  5. Lägg till hanteraren för verifiering av MFA-utmaningen:

    async submitMfaChallenge() {
        this.error = "";
        this.loading = true;
    
        if (!this.mfaChallenge) {
            this.error = "Please enter a code.";
            this.loading = false;
            return;
        }
    
        if (this.signInState instanceof MfaVerificationRequiredState) {
            const result = await this.signInState.submitChallenge(this.mfaChallenge);
    
            if (result.isFailed()) {
                if (result.error?.isIncorrectChallenge()) {
                    this.error = "Incorrect code.";
                } else {
                    this.error =
                        result.error?.errorData?.errorDescription ||
                        "An error occurred while verifying the challenge response.";
                }
            }
    
            if (result.isCompleted()) {
                this.isSignedIn = true;
                this.userData = result.data;
                this.showMfaChallenge = false;
                this.signInState = result.state;
            }
        }
        this.loading = false;
    }
    
  6. Uppdatera filerna /src/app/components/sign-in/sign-in.component.html för att visa rätt MFA-utmaningsformulär (val av MFA-utmaningsmetod eller verifiering av MFA-utmaningsmetod):

    <!-- Use shared MFA auth method selection form -->
    <app-mfa-auth-method-selection-form *ngIf="showMfaAuthMethods" [authMethods]="mfaAuthMethods"
        [selectedAuthMethod]="selectedMfaAuthMethod" [loading]="loading"
        (selectedAuthMethodChange)="selectedMfaAuthMethod = $event" (submitForm)="submitMfaAuthMethod()">
    </app-mfa-auth-method-selection-form>
    
    <!-- Use shared MFA challenge form -->
    <app-mfa-challenge-form *ngIf="showMfaChallenge" [challenge]="mfaChallenge" [loading]="loading"
        (challengeChange)="mfaChallenge = $event" (submitForm)="submitMfaChallenge()">
    </app-mfa-challenge-form>
    

Hantera multifaktorautentisering efter registrering eller lösenordsåterställning

MFA-flödet efter registrering och lösenordsåterställning fungerar ungefär som MFA i inloggningsflödet. Efter en lyckad registrering eller lösenordsåterställning kan SDK:t automatiskt fortsätta med inloggningsflödet. Om användaren har en stark autentiseringsmetod registrerad övergår flödet till MFA-utmaningsverifiering.

Hantera multifaktorautentisering efter registrering

För MFA-flöde efter registrering behöver du uppdatera filen /src/app/components/sign-up/sign-up.component.ts . Se den fullständiga koden i sign-up.component.ts:

  1. Kontrollera att du importerar de typer och komponenter som krävs.

  2. Hantera MFA-kravtillstånd på ett liknande sätt som i inloggningsflödet. När registreringen har slutförts använder du resultatet för att automatiskt utlösa ett inloggningsflöde enligt följande kodfragment:

    // In your sign-up completion handler
    if (this.signUpState instanceof SignUpCompletedState) {
        const result = await this.signUpState.signIn();
    
        ...
    
        if (result.isMfaRequired()) {
            this.showMfaAuthMethods = true;
            this.showPassword = false;
            this.showCode = false;
            this.showAuthMethodsForRegistration = false;
            this.showChallengeForRegistration = false;
            this.showMfaChallenge = false;
            this.mfaAuthMethods = result.state.getAuthMethods();
            // Set default selection to the first MFA auth method
            this.selectedMfaAuthMethod = this.mfaAuthMethods.length > 0 ? this.mfaAuthMethods[0] : undefined;
            this.signUpState = result.state;
        }
    
        ...
    }
    
  3. Uppdatera filen /src/app/components/sign-up/sign-up.component.html för att lägga till MFA-formulär (MFA-metodvalsformulär och MFA-formulär för verifiering av MFA-utmaning). Se ett fullständigt exempel i sign-up.component.html.

Hantera multifaktorautentisering efter lösenordsåterställning

För MFA-flöde efter SSPR behöver du uppdatera filen /src/app/components/reset-password/reset-password.component.ts . Se den fullständiga koden i reset-password.component.ts:

  1. Kontrollera att du importerar de typer och komponenter som krävs.

  2. Hantera MFA-kravtillstånd på ett liknande sätt som i inloggningsflödet. När registreringen har slutförts använder du resultatet för att automatiskt utlösa ett inloggningsflöde enligt följande kodfragment:

    if (this.resetState instanceof ResetPasswordCompletedState) {
        const result = await this.resetState.signIn();
    
        ...
    
        if (result.isMfaRequired()) {
            this.showMfaAuthMethods = true;
            this.showCode = false;
            this.showNewPassword = false;
            this.showAuthMethodsForRegistration = false;
            this.showChallengeForRegistration = false;
            this.showMfaChallenge = false;
            this.isReset = false;
            this.mfaAuthMethods = result.state.getAuthMethods();
            // Set default selection to the first MFA auth method
            this.selectedMfaAuthMethod = this.mfaAuthMethods.length > 0 ? this.mfaAuthMethods[0] : undefined;
            this.resetState = result.state;
        }
    
        ...
    }
    
  3. Uppdatera din /src/app/components/reset-password/reset-password.component.html fil för att lägga till MFA-formulär (MFA-metodvalsformulär och MFA-formulär för verifiering av MFA-utmaning). Se ett fullständigt exempel i reset-password.component.html.

Köra och testa din app

Innan du testar din app kontrollerar du att du har ett användarkonto som har en registrerad stark autentiseringsmetod. Använd stegen i Kör och testa din app för att köra din app, men den här gången testar du MFA-flödet.