Oefening: gebruikersverificatie toevoegen
Uw boodschappenlijstweb-app heeft gebruikersverificatie nodig. In deze oefening implementeert u aanmelding en afmelding in uw app en geeft u de huidige aanmeldingsstatus van de gebruiker weer.
In deze oefening voert u de volgende stappen uit:
- Installeer de Static Web Apps CLI voor lokale ontwikkeling.
- Voer de app en API lokaal uit met lokale verificatie-emulatie.
- Voeg aanmeldingsknoppen toe voor meerdere verificatieproviders.
- Voeg een afmeldingsknop toe als de gebruiker is aangemeld.
- De aanmeldingsstatus van de gebruiker weergeven.
- Test de verificatiewerkstroom lokaal.
- Implementeer de bijgewerkte app.
Voorbereiden op lokale ontwikkeling
De Static Web Apps CLI, ook wel SWA CLI genoemd, is een lokaal ontwikkelprogramma waarmee u uw web-app en API lokaal kunt uitvoeren en verificatie- en autorisatieservers kunt emuleren.
Open een terminal op uw computer.
Installeer de SWA CLI met de volgende opdracht.
npm install -g @azure/static-web-apps-cli
De app lokaal uitvoeren
Voer nu de app en API lokaal uit met een ontwikkelserver. Op deze manier kunt u uw wijzigingen zien en testen terwijl u ze in de code aanbrengt.
Open het project in Visual Studio Code.
Open in Visual Studio Code het opdrachtpalet door op F1 te drukken.
Voer Terminal in en selecteer Deze: Nieuwe geïntegreerde terminal maken.
Ga als volgt naar de map van uw favoriete front-endframework:
cd angular-app
cd react-app
cd svelte-app
cd vue-app
Voer de front-endclienttoepassing uit met behulp van een ontwikkelserver.
npm start
npm start
npm run dev
npm run serve
Laat deze server op de achtergrond draaien. Voer nu de API- en verificatieserveremulator uit met behulp van de SWA CLI.
Open in Visual Studio Code het opdrachtpalet door op F1 te drukken.
Voer Terminal in en selecteer Deze: Nieuwe geïntegreerde terminal maken.
Voer de SWA CLI uit door de volgende opdracht uit te voeren:
swa start http://localhost:4200 --api-location ./api
swa start http://localhost:3000 --api-location ./api
swa start http://localhost:5000 --api-location ./api
swa start http://localhost:8080 --api-location ./api
Blader naar
http://localhost:4280
.
De laatste poort die door de SWA CLI wordt gebruikt, verschilt van de poort die u eerder hebt gezien, omdat er een omgekeerde proxy wordt gebruikt om aanvragen door te sturen naar de drie verschillende onderdelen:
- Uw frameworkontwikkelingsserver
- De verificatie- en autorisatieemulator
- De API die wordt gehost door de Functions-runtime
Laat de toepassing actief blijven terwijl u de code wijzigt.
De aanmeldingsstatus van de gebruiker ophalen
Eerst moet u toegang krijgen tot de aanmeldingsstatus van de gebruiker door een query naar de client te /.auth/me
maken.
Maak het bestand
angular-app/src/app/core/models/user-info.ts
en voeg de volgende code toe om de interface voor de gebruikersgegevens weer te geven.export interface UserInfo { identityProvider: string; userId: string; userDetails: string; userRoles: string[]; }
Bewerk het bestand
angular-app/src/app/core/components/nav.component.ts
en voeg de volgende methode toe aan deNavComponent
klasse.async getUserInfo() { try { const response = await fetch('/.auth/me'); const payload = await response.json(); const { clientPrincipal } = payload; return clientPrincipal; } catch (error) { console.error('No profile could be found'); return undefined; } }
Maak een nieuwe klasse-eigenschap
userInfo
en sla het resultaat van de asynchrone functiegetUserInfo()
op wanneer het onderdeel wordt geïnitialiseerd. Implementeer deOnInit
interface en werk de importinstructies bij om te importerenOnInit
enUserInfo
. Met deze code worden de gebruikersgegevens opgehaald wanneer het onderdeel wordt geïnitialiseerd.import { Component, OnInit } from '@angular/core'; import { UserInfo } from '../model/user-info'; export class NavComponent implements OnInit { userInfo: UserInfo; async ngOnInit() { this.userInfo = await this.getUserInfo(); } // ... }
Bewerk het bestand
react-app/src/components/NavBar.js
en voeg de volgende code toe boven aan de functie. Met deze code worden de gebruikersgegevens opgehaald wanneer het onderdeel wordt geladen en opgeslagen in de status.import React, { useState, useEffect } from 'react'; import { NavLink } from 'react-router-dom'; const NavBar = (props) => { const [userInfo, setUserInfo] = useState(); useEffect(() => { (async () => { setUserInfo(await getUserInfo()); })(); }, []); async function getUserInfo() { try { const response = await fetch('/.auth/me'); const payload = await response.json(); const { clientPrincipal } = payload; return clientPrincipal; } catch (error) { console.error('No profile could be found'); return undefined; } } return ( // ...
Bewerk het bestand
svelte-app/src/components/NavBar.svelte
en voeg de volgende code toe in de scriptsectie. Met deze code worden de gebruikersgegevens opgehaald wanneer het onderdeel wordt geladen.import { onMount } from 'svelte'; let userInfo = undefined; onMount(async () => (userInfo = await getUserInfo())); async function getUserInfo() { try { const response = await fetch('/.auth/me'); const payload = await response.json(); const { clientPrincipal } = payload; return clientPrincipal; } catch (error) { console.error('No profile could be found'); return undefined; } }
Bewerk het bestand
vue-app/src/components/nav-bar.vue
en voeg dit toeuserInfo
aan het gegevensobject.data() { return { userInfo: { type: Object, default() {}, }, }; },
Voeg de
getUserInfo()
methode toe aan de sectie Methoden .methods: { async getUserInfo() { try { const response = await fetch('/.auth/me'); const payload = await response.json(); const { clientPrincipal } = payload; return clientPrincipal; } catch (error) { console.error('No profile could be found'); return undefined; } }, },
Voeg de
created
levenscyclushook toe aan het onderdeel.async created() { this.userInfo = await this.getUserInfo(); },
Wanneer het onderdeel wordt gemaakt, worden de gebruikersgegevens automatisch opgehaald.
Aanmeldings- en afmeldingsknoppen toevoegen
De gebruikersgegevens zijn undefined
als ze niet zijn aangemeld, zodat de wijzigingen voorlopig niet zichtbaar zijn. Het is tijd om aanmeldingsknoppen toe te voegen voor de verschillende providers.
Bewerk het bestand
angular-app/src/app/core/components/nav.component.ts
om een lijst met providers toe te voegen in deNavComponent
klasse.providers = ['x', 'github', 'aad'];
Voeg de volgende
redirect
eigenschap toe om de huidige URL voor de omleiding na aanmelding vast te leggen.redirect = window.location.pathname;
Voeg de volgende code toe aan de sjabloon na het eerste
</nav>
element om de aanmeldings- en afmeldingsknoppen weer te geven.<nav class="menu auth"> <p class="menu-label">Auth</p> <div class="menu-list auth"> <ng-container *ngIf="!userInfo; else logout"> <ng-container *ngFor="let provider of providers"> <a href="/.auth/login/{{provider}}?post_login_redirect_uri={{redirect}}">{{provider}}</a> </ng-container> </ng-container> <ng-template #logout> <a href="/.auth/logout?post_logout_redirect_uri={{redirect}}">Logout</a> </ng-template> </div> </nav>
Als de gebruiker niet is aangemeld, geeft u de aanmeldingsknop voor elke provider weer. Elke knop wordt gekoppeld aan
/.auth/login/<AUTH_PROVIDER>
en stelt de omleidings-URL in op de huidige pagina.Als de gebruiker al is aangemeld, wordt met een afmeldingsknop deze koppelingen weergegeven
/.auth/logout
en wordt ook de omleidings-URL ingesteld op de huidige pagina.
U ziet deze webpagina nu in uw browser.
Bewerk het bestand
react-app/src/components/NavBar.js
om een lijst met providers boven aan de functie toe te voegen.const providers = ['x', 'github', 'aad'];
Voeg de volgende
redirect
variabele toe onder de eerste variabele om de huidige URL voor de omleiding na aanmelding vast te leggen.const redirect = window.location.pathname;
Voeg de volgende code toe aan de JSX-sjabloon na het eerste
</nav>
element om de aanmeldings- en afmeldingsknoppen weer te geven.<nav className="menu auth"> <p className="menu-label">Auth</p> <div className="menu-list auth"> {!userInfo && providers.map((provider) => ( <a key={provider} href={`/.auth/login/${provider}?post_login_redirect_uri=${redirect}`}> {provider} </a> ))} {userInfo && <a href={`/.auth/logout?post_logout_redirect_uri=${redirect}`}>Logout</a>} </div> </nav>
Als de gebruiker niet is aangemeld, geeft u de aanmeldingsknop voor elke provider weer. Elke knop wordt gekoppeld aan
/.auth/login/<AUTH_PROVIDER>
en stelt de omleidings-URL in op de huidige pagina.Als de gebruiker al is aangemeld, geeft u een afmeldingsknop weer waarnaar wordt verwezen
/.auth/logout
en stelt u ook de omleidings-URL in op de huidige pagina.
U ziet deze webpagina nu in uw browser.
Bewerk het bestand
svelte-app/src/components/NavBar.svelte
om een lijst met providers boven aan het script toe te voegen.const providers = ['x', 'github', 'aad'];
Voeg de volgende
redirect
variabele toe onder de eerste variabele om de huidige URL voor de omleiding na aanmelding vast te leggen.const redirect = window.location.pathname;
Voeg de volgende code toe aan de sjabloon na het eerste
</nav>
element om de aanmeldings- en afmeldingsknoppen weer te geven.<nav class="menu auth"> <p class="menu-label">Auth</p> <div class="menu-list auth"> {#if !userInfo} {#each providers as provider (provider)} <a href={`/.auth/login/${provider}?post_login_redirect_uri=${redirect}`}> {provider} </a> {/each} {/if} {#if userInfo} <a href={`/.auth/logout?post_logout_redirect_uri=${redirect}`}> Logout </a> {/if} </div> </nav>
Als de gebruiker niet is aangemeld, geeft u de aanmeldingsknop voor elke provider weer. Elke knop wordt gekoppeld aan
/.auth/login/<AUTH_PROVIDER>
en stelt de omleidings-URL in op de huidige pagina.Als de gebruiker al is aangemeld, geeft u een afmeldingsknop weer waarnaar wordt verwezen
/.auth/logout
en stelt u ook de omleidings-URL in op de huidige pagina.
U ziet deze webpagina nu in uw browser.
Bewerk het bestand
vue-app/src/components/nav-bar.vue
en voeg een lijst met providers toe aan het gegevensobject.providers: ['x', 'github', 'aad'],
Voeg de volgende
redirect
eigenschap toe om de huidige URL voor de omleiding na aanmelding vast te leggen.redirect: window.location.pathname,
Voeg de volgende code toe aan de sjabloon na het eerste
</nav>
element om de aanmeldings- en afmeldingsknoppen weer te geven.<nav class="menu auth"> <p class="menu-label">Auth</p> <div class="menu-list auth"> <template v-if="!userInfo"> <template v-for="provider in providers"> <a :key="provider" :href="`/.auth/login/${provider}?post_login_redirect_uri=${redirect}`"> {{ provider }} </a> </template> </template> <a v-if="userInfo" :href="`/.auth/login/${provider}?post_login_redirect_uri=${redirect}`"> Logout </a> </div> </nav>
Als de gebruiker niet is aangemeld, geeft u de aanmeldingsknop voor elke provider weer. Elke knop wordt gekoppeld aan
/.auth/login/<AUTH_PROVIDER>
en stelt de omleidings-URL in op de huidige pagina.Als de gebruiker al is aangemeld, geeft u een afmeldingsknop weer waarnaar wordt verwezen
/.auth/logout
en stelt u ook de omleidings-URL in op de huidige pagina.
U ziet deze webpagina nu in uw browser.
De aanmeldingsstatus van de gebruiker weergeven
Voordat u de verificatiewerkstroom test, laten we de gebruikersdetails over de aangemelde gebruiker weergeven.
Bewerk het bestand angular-app/src/app/core/components/nav.component.ts
en voeg deze code onder aan de sjabloon toe na de laatste afsluitende </nav>
tag.
<div class="user" *ngIf="userInfo">
<p>Welcome</p>
<p>{{ userInfo?.userDetails }}</p>
<p>{{ userInfo?.identityProvider }}</p>
</div>
Notitie
De userDetails
eigenschap kan een gebruikersnaam of e-mailadres zijn, afhankelijk van de identiteit die is opgegeven om u aan te melden.
Het voltooide bestand ziet er nu als volgt uit:
import { Component, OnInit } from '@angular/core';
import { UserInfo } from '../model/user-info';
@Component({
selector: 'app-nav',
template: `
<nav class="menu">
<p class="menu-label">Menu</p>
<ul class="menu-list">
<a routerLink="/products" routerLinkActive="router-link-active">
<span>Products</span>
</a>
<a routerLink="/about" routerLinkActive="router-link-active">
<span>About</span>
</a>
</ul>
</nav>
<nav class="menu auth">
<p class="menu-label">Auth</p>
<div class="menu-list auth">
<ng-container *ngIf="!userInfo; else logout">
<ng-container *ngFor="let provider of providers">
<a href="/.auth/login/{{ provider }}?post_login_redirect_uri={{ redirect }}">{{ provider }}</a>
</ng-container>
</ng-container>
<ng-template #logout>
<a href="/.auth/logout?post_logout_redirect_uri={{ redirect }}">Logout</a>
</ng-template>
</div>
</nav>
<div class="user" *ngIf="userInfo">
<p>Welcome</p>
<p>{{ userInfo?.userDetails }}</p>
<p>{{ userInfo?.identityProvider }}</p>
</div>
`,
})
export class NavComponent implements OnInit {
providers = ['x', 'github', 'aad'];
redirect = window.location.pathname;
userInfo: UserInfo;
async ngOnInit() {
this.userInfo = await this.getUserInfo();
}
async getUserInfo() {
try {
const response = await fetch('/.auth/me');
const payload = await response.json();
const { clientPrincipal } = payload;
return clientPrincipal;
} catch (error) {
console.error('No profile could be found');
return undefined;
}
}
}
Bewerk het bestand react-app/src/components/NavBar.js
en voeg deze code toe aan de onderkant van de JSX-sjabloon na de laatste slottag </nav>
om de aanmeldingsstatus weer te geven.
{
userInfo && (
<div>
<div className="user">
<p>Welcome</p>
<p>{userInfo && userInfo.userDetails}</p>
<p>{userInfo && userInfo.identityProvider}</p>
</div>
</div>
)
}
Notitie
De userDetails
eigenschap kan een gebruikersnaam of e-mailadres zijn, afhankelijk van de identiteit die is opgegeven om u aan te melden.
Het voltooide bestand ziet er nu als volgt uit:
import React, { useState, useEffect } from 'react';
import { NavLink } from 'react-router-dom';
const NavBar = (props) => {
const providers = ['x', 'github', 'aad'];
const redirect = window.location.pathname;
const [userInfo, setUserInfo] = useState();
useEffect(() => {
(async () => {
setUserInfo(await getUserInfo());
})();
}, []);
async function getUserInfo() {
try {
const response = await fetch('/.auth/me');
const payload = await response.json();
const { clientPrincipal } = payload;
return clientPrincipal;
} catch (error) {
console.error('No profile could be found');
return undefined;
}
}
return (
<div className="column is-2">
<nav className="menu">
<p className="menu-label">Menu</p>
<ul className="menu-list">
<NavLink to="/products" activeClassName="active-link">
Products
</NavLink>
<NavLink to="/about" activeClassName="active-link">
About
</NavLink>
</ul>
{props.children}
</nav>
<nav className="menu auth">
<p className="menu-label">Auth</p>
<div className="menu-list auth">
{!userInfo &&
providers.map((provider) => (
<a key={provider} href={`/.auth/login/${provider}?post_login_redirect_uri=${redirect}`}>
{provider}
</a>
))}
{userInfo && <a href={`/.auth/logout?post_logout_redirect_uri=${redirect}`}>Logout</a>}
</div>
</nav>
{userInfo && (
<div>
<div className="user">
<p>Welcome</p>
<p>{userInfo && userInfo.userDetails}</p>
<p>{userInfo && userInfo.identityProvider}</p>
</div>
</div>
)}
</div>
);
};
export default NavBar;
Bewerk het bestand svelte-app/src/components/NavBar.svelte
en voeg deze code onder aan de sjabloon toe na de laatste afsluitende </nav>
tag om de aanmeldingsstatus weer te geven.
{#if userInfo}
<div class="user">
<p>Welcome</p>
<p>{userInfo && userInfo.userDetails}</p>
<p>{userInfo && userInfo.identityProvider}</p>
</div>
{/if}
Notitie
De userDetails
eigenschap kan een gebruikersnaam of e-mailadres zijn, afhankelijk van de identiteit die is opgegeven om u aan te melden.
Het voltooide bestand ziet er nu als volgt uit:
<script>
import { onMount } from 'svelte';
import { Link } from 'svelte-routing';
const providers = ['x', 'github', 'aad'];
const redirect = window.location.pathname;
let userInfo = undefined;
onMount(async () => (userInfo = await getUserInfo()));
async function getUserInfo() {
try {
const response = await fetch('/.auth/me');
const payload = await response.json();
const { clientPrincipal } = payload;
return clientPrincipal;
} catch (error) {
console.error('No profile could be found');
return undefined;
}
}
function getProps({ href, isPartiallyCurrent, isCurrent }) {
const isActive = href === '/' ? isCurrent : isPartiallyCurrent || isCurrent;
// The object returned here is spread on the anchor element's attributes
if (isActive) {
return { class: 'router-link-active' };
}
return {};
}
</script>
<div class="column is-2">
<nav class="menu">
<p class="menu-label">Menu</p>
<ul class="menu-list">
<Link to="/products" {getProps}>Products</Link>
<Link to="/about" {getProps}>About</Link>
</ul>
</nav>
<nav class="menu auth">
<p class="menu-label">Auth</p>
<div class="menu-list auth">
{#if !userInfo}
{#each providers as provider (provider)}
<a href={`/.auth/login/${provider}?post_login_redirect_uri=${redirect}`}>
{provider}
</a>
{/each}
{/if}
{#if userInfo}
<a href={`/.auth/logout?post_logout_redirect_uri=${redirect}`}>
Logout
</a>
{/if}
</div>
</nav>
{#if userInfo}
<div class="user">
<p>Welcome</p>
<p>{userInfo && userInfo.userDetails}</p>
<p>{userInfo && userInfo.identityProvider}</p>
</div>
{/if}
</div>
Bewerk het bestand vue-app/src/components/nav-bar.vue
en voeg deze code onder aan de sjabloon toe na de laatste afsluitende </nav>
tag om de aanmeldingsstatus weer te geven:
<div class="user" v-if="userInfo">
<p>Welcome</p>
<p>{{ userInfo.userDetails }}</p>
<p>{{ userInfo.identityProvider }}</p>
</div>
Notitie
De userDetails
eigenschap kan een gebruikersnaam of e-mailadres zijn, afhankelijk van de identiteit die is opgegeven om u aan te melden.
Het voltooide bestand ziet er nu als volgt uit:
<script>
export default {
name: 'NavBar',
data() {
return {
userInfo: {
type: Object,
default() {},
},
providers: ['x', 'github', 'aad'],
redirect: window.location.pathname,
};
},
methods: {
async getUserInfo() {
try {
const response = await fetch('/.auth/me');
const payload = await response.json();
const { clientPrincipal } = payload;
return clientPrincipal;
} catch (error) {
console.error('No profile could be found');
return undefined;
}
},
},
async created() {
this.userInfo = await this.getUserInfo();
},
};
</script>
<template>
<div column is-2>
<nav class="menu">
<p class="menu-label">Menu</p>
<ul class="menu-list">
<router-link to="/products">Products</router-link>
<router-link to="/about">About</router-link>
</ul>
</nav>
<nav class="menu auth">
<p class="menu-label">Auth</p>
<div class="menu-list auth">
<template v-if="!userInfo">
<template v-for="provider in providers">
<a :key="provider" :href="`/.auth/login/${provider}?post_login_redirect_uri=${redirect}`">{{ provider }}</a>
</template>
</template>
<a v-if="userInfo" :href="`/.auth/logout?post_logout_redirect_uri=${redirect}`">Logout</a>
</div>
</nav>
<div class="user" v-if="userInfo">
<p>Welcome</p>
<p>{{ userInfo.userDetails }}</p>
<p>{{ userInfo.identityProvider }}</p>
</div>
</div>
</template>
Verificatie lokaal testen
Alles is nu aanwezig. De laatste stap is om te testen of alles werkt zoals verwacht.
Selecteer in uw web-app een van de id-providers om u aan te melden.
U wordt omgeleid naar deze pagina:
Dit is een nepverificatiescherm, geleverd door de SWA CLI, zodat u verificatie lokaal kunt testen door uzelf gebruikersgegevens op te geven.
Voer
mslearn
in als gebruikersnaam en1234
voor de gebruikers-id.Selecteer Aanmelden.
Na de aanmelding wordt u omgeleid naar de vorige pagina. U kunt zien dat de aanmeldingsknoppen zijn vervangen door een afmeldingsknop. U kunt ook uw gebruikersnaam en de geselecteerde provider onder de afmeldingsknop zien.
Nu u hebt gecontroleerd of alles lokaal werkt zoals verwacht, is het tijd om uw wijzigingen te implementeren.
U kunt de actieve app en API stoppen door op Ctrl-C in beide terminals te drukken.
Uw wijzigingen implementeren
Open in Visual Studio Code het opdrachtpalet door op F1 te drukken.
Voer Git in en selecteer Alles doorvoeren.
Voer het
Add authentication
doorvoerbericht in en druk op Enter.Druk op F1 om het opdrachtenpalet te openen.
Enter en selecteer Git: Push en druk op Enter.
Nadat u de wijzigingen hebt gepusht, wacht u tot het build- en implementatieproces is uitgevoerd. De wijzigingen moeten daarna zichtbaar zijn in uw geïmplementeerde app.
Volgende stappen
Uw app ondersteunt nu gebruikersverificatie en de volgende stap is het beperken van sommige onderdelen van de app tot niet-geverifieerde gebruikers.