Latihan - Menambahkan autentikasi pengguna
Aplikasi web daftar belanja Anda memerlukan autentikasi pengguna. Dalam latihan ini, Anda akan menerapkan masuk dan keluar di aplikasi Anda, dan menampilkan status masuk pengguna saat ini.
Dalam latihan ini, Anda akan menyelesaikan langkah berikut:
- Instal Azure Static Web Apps CLI untuk pengembangan lokal.
- Jalankan aplikasi dan API secara lokal dengan emulasi autentikasi lokal.
- Tambahkan tombol masuk untuk beberapa penyedia autentikasi.
- Tambahkan tombol keluar jika pengguna masuk.
- Tampilkan status masuk pengguna.
- Uji alur kerja autentikasi secara lokal.
- Sebarkan aplikasi yang diperbarui.
Bersiap untuk pengembangan lokal
Azure Static Web Apps CLI, juga dikenal sebagai SWA CLI, adalah alat pengembangan lokal yang memungkinkan Anda menjalankan aplikasi web dan API Anda secara lokal dan meniru server autentikasi dan otorisasi.
Buka terminal pada komputer Anda.
Menginstal SWA CLI yang menjalankan perintah berikut.
npm install -g @azure/static-web-apps-cli
Menjalankan aplikasi secara lokal
Sekarang jalankan aplikasi dan API secara lokal dengan server pengembangan. Dengan cara ini, Anda akan dapat melihat dan menguji perubahan yang dibuat, saat membuat kodenya.
Buka proyek di Visual Studio Code.
Di Visual Studio Code, buka palet perintah dengan menekan F1.
Masuk dan pilih Terminal: Buat Terminal Terpadu Baru.
Buka folder kerangka kerja front-end pilihan Anda, sebagai berikut:
cd angular-app
cd react-app
cd svelte-app
cd vue-app
Jalankan aplikasi klien ujung depan menggunakan server pengembangan.
npm start
npm start
npm run dev
npm run serve
Biarkan server ini berjalan di latar-belakang. Sekarang jalankan API dan emulator server autentikasi menggunakan SWA CLI.
Di Visual Studio Code, buka palet perintah dengan menekan F1.
Masuk dan pilih Terminal: Buat Terminal Terpadu Baru.
Jalankan CLI SWA dengan menjalankan perintah berikut:
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
Telusuri
http://localhost:4280
.
Port akhir yang digunakan oleh SWA CLI berbeda dari yang pernah Anda lihat sebelumnya, karena ini menggunakan proksi terbalik untuk meneruskan permintaan ke tiga komponen berbeda:
- Server pengembangan kerangka kerja Anda
- Emulator autentikasi dan otorisasi
- API yang dihost oleh runtime Functions
Biarkan aplikasi tetap berjalan saat Anda memodifikasi kode.
Mendapatkan status masuk pengguna
Pertama, Anda perlu mengakses status masuk pengguna dengan membuat kueri ke /.auth/me
di klien.
Buat file
angular-app/src/app/core/models/user-info.ts
dan tambahkan kode berikut untuk merepresentasikan antarmuka untuk informasi pengguna.export interface UserInfo { identityProvider: string; userId: string; userDetails: string; userRoles: string[]; }
Edit file
angular-app/src/app/core/components/nav.component.ts
, dan tambahkan metode berikut di kelasNavComponent
.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; } }
Buat properti kelas baru
userInfo
dan simpan hasil fungsi asinkrongetUserInfo()
saat komponen diinisialisasi. Terapkan antarmukaOnInit
dan perbarui pernyataan impor untuk mengimporOnInit
danUserInfo
. Kode ini mengambil informasi pengguna ketika komponen diinisialisasi.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(); } // ... }
Edit file
react-app/src/components/NavBar.js
dan tambahkan kode berikut di bagian atas fungsi. Kode ini mengambil informasi pengguna ketika komponen memuat dan menyimpan informasi pengguna ke dalam 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 ( // ...
Edit file
svelte-app/src/components/NavBar.svelte
dan tambahkan kode berikut di bagian skrip. Kode ini mengambil informasi pengguna ketika komponen memuat.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; } }
Edit file
vue-app/src/components/nav-bar.vue
, dan tambahkanuserInfo
ke objek data.data() { return { userInfo: { type: Object, default() {}, }, }; },
Tambahkan metode
getUserInfo()
ke bagian metode.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; } }, },
Tambahkan hook siklus hidup
created
ke komponen.async created() { this.userInfo = await this.getUserInfo(); },
Ketika komponen dibuat, informasi pengguna diambil secara otomatis.
Menambahkan tombol masuk dan keluar
Informasi pengguna akan menjadi undefined
jika pengguna tidak masuk, sehingga perubahan tidak akan terlihat untuk saat ini. Saatnya menambahkan tombol masuk untuk penyedia yang berbeda.
Edit file
angular-app/src/app/core/components/nav.component.ts
untuk menambahkan daftar penyedia di kelasNavComponent
.providers = ['twitter', 'github', 'aad'];
Tambahkan properti
redirect
berikut untuk menangkap URL saat ini untuk pengalihan pasca masuk.redirect = window.location.pathname;
Tambahkan kode berikut ke templat setelah elemen
</nav>
pertama untuk menampilkan tombol masuk dan keluar.<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>
Jika pengguna tidak masuk, Anda menampilkan tombol masuk untuk setiap penyedia. Setiap tombol ditautkan ke
/.auth/login/<AUTH_PROVIDER>
, dan menyetel URL pengalihan ke halaman saat ini.Jika tidak, saat pengguna sudah masuk, tombol keluar menampilkan yang ditautkan ke
/.auth/logout
dan juga mengatur URL pengalihan ke halaman saat ini.
Anda kini akan melihat halaman web ini di browser.
Edit file
react-app/src/components/NavBar.js
untuk menambahkan daftar penyedia di bagian atas fungsi.const providers = ['twitter', 'github', 'aad'];
Tambahkan variabel
redirect
berikut di bagian variabel pertama guna menangkap URL saat ini untuk pengalihan pasca masuk.const redirect = window.location.pathname;
Tambahkan kode berikut ke templat JSX setelah elemen
</nav>
pertama untuk menampilkan tombol masuk dan keluar.<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>
Jika pengguna tidak masuk, Anda menampilkan tombol masuk untuk setiap penyedia. Setiap tombol ditautkan ke
/.auth/login/<AUTH_PROVIDER>
, dan menyetel URL pengalihan ke halaman saat ini.Jika tidak, saat pengguna sudah masuk, Anda akan menampilkan tombol keluar yang ditautkan ke
/.auth/logout
dan juga menyetel URL pengalihan ke halaman saat ini.
Anda kini akan melihat halaman web ini di browser.
Edit file
svelte-app/src/components/NavBar.svelte
untuk menambahkan daftar penyedia di bagian atas skrip.const providers = ['twitter', 'github', 'aad'];
Tambahkan variabel
redirect
berikut di bagian variabel pertama guna menangkap URL saat ini untuk pengalihan pasca masuk.const redirect = window.location.pathname;
Tambahkan kode berikut ke templat setelah elemen
</nav>
pertama untuk menampilkan tombol masuk dan keluar.<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>
Jika pengguna tidak masuk, Anda menampilkan tombol masuk untuk setiap penyedia. Setiap tombol ditautkan ke
/.auth/login/<AUTH_PROVIDER>
, dan menyetel URL pengalihan ke halaman saat ini.Jika tidak, saat pengguna sudah masuk, Anda akan menampilkan tombol keluar yang ditautkan ke
/.auth/logout
dan juga menyetel URL pengalihan ke halaman saat ini.
Anda kini akan melihat halaman web ini di browser.
Edit file
vue-app/src/components/nav-bar.vue
, dan tambahkan daftar penyedia ke objek data.providers: ['twitter', 'github', 'aad'],
Tambahkan properti
redirect
berikut guna menangkap URL saat ini untuk pengalihan pasca masuk.redirect: window.location.pathname,
Tambahkan kode berikut ke templat setelah elemen
</nav>
pertama untuk menampilkan tombol masuk dan keluar.<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>
Jika pengguna tidak masuk, Anda menampilkan tombol masuk untuk setiap penyedia. Setiap tombol ditautkan ke
/.auth/login/<AUTH_PROVIDER>
, dan menyetel URL pengalihan ke halaman saat ini.Jika tidak, saat pengguna sudah masuk, Anda akan menampilkan tombol keluar yang ditautkan ke
/.auth/logout
dan juga menyetel URL pengalihan ke halaman saat ini.
Anda kini akan melihat halaman web ini di browser.
Menampilkan status masuk pengguna
Sebelum menguji alur kerja autentikasi, tampilkan detail pengguna terkait pengguna yang masuk.
Edit file angular-app/src/app/core/components/nav.component.ts
dan tambahkan kode ini ke bagian bawah templat setelah tag </nav>
penutup terakhir.
<div class="user" *ngIf="userInfo">
<p>Welcome</p>
<p>{{ userInfo?.userDetails }}</p>
<p>{{ userInfo?.identityProvider }}</p>
</div>
Catatan
Properti userDetails
dapat berupa nama pengguna atau alamat email, tergantung identitas yang disediakan untuk masuk.
File Anda yang sudah selesai sekarang akan terlihat seperti berikut:
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 = ['twitter', '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;
}
}
}
Edit file react-app/src/components/NavBar.js
dan tambahkan kode ini ke bagian bawah templat JSX setelah tag </nav>
penutup terakhir, untuk menampilkan status masuk.
{
userInfo && (
<div>
<div className="user">
<p>Welcome</p>
<p>{userInfo && userInfo.userDetails}</p>
<p>{userInfo && userInfo.identityProvider}</p>
</div>
</div>
)
}
Catatan
Properti userDetails
dapat berupa nama pengguna atau alamat email, tergantung identitas yang disediakan untuk masuk.
File Anda yang sudah selesai sekarang akan terlihat seperti berikut:
import React, { useState, useEffect } from 'react';
import { NavLink } from 'react-router-dom';
const NavBar = (props) => {
const providers = ['twitter', '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;
Edit file svelte-app/src/components/NavBar.svelte
dan tambahkan kode ini ke bagian bawah templat setelah tag </nav>
penutup terakhir, untuk menampilkan status masuk.
{#if userInfo}
<div class="user">
<p>Welcome</p>
<p>{userInfo && userInfo.userDetails}</p>
<p>{userInfo && userInfo.identityProvider}</p>
</div>
{/if}
Catatan
Properti userDetails
dapat berupa nama pengguna atau alamat email, tergantung identitas yang disediakan untuk masuk.
File Anda yang sudah selesai sekarang akan terlihat seperti berikut:
<script>
import { onMount } from 'svelte';
import { Link } from 'svelte-routing';
const providers = ['twitter', '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>
Edit file vue-app/src/components/nav-bar.vue
, dan tambahkan kode ini ke bagian bawah templat setelah tag </nav>
penutup terakhir, untuk menampilkan status masuk:
<div class="user" v-if="userInfo">
<p>Welcome</p>
<p>{{ userInfo.userDetails }}</p>
<p>{{ userInfo.identityProvider }}</p>
</div>
Catatan
Properti userDetails
dapat berupa nama pengguna atau alamat email, tergantung identitas yang disediakan untuk masuk.
File Anda yang sudah selesai sekarang akan terlihat seperti berikut:
<script>
export default {
name: 'NavBar',
data() {
return {
userInfo: {
type: Object,
default() {},
},
providers: ['twitter', '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>
Menguji autentikasi secara lokal
Semuanya sekarang sudah diatur. Langkah terakhir adalah menguji apakah semuanya berfungsi seperti yang diharapkan.
Di aplikasi web Anda, pilih salah satu penyedia identitas untuk masuk.
Anda akan diarahkan ke halaman ini:
Ini adalah layar autentikasi palsu, yang disediakan oleh CLI SWA, memungkinkan Anda menguji autentikasi secara lokal dengan memberikan detail pengguna kepada diri Anda sendiri.
Masukkan
mslearn
sebagai nama pengguna dan1234
untuk ID pengguna.Pilih Masuk.
Setelah masuk, Anda diarahkan ke halaman sebelumnya. Anda dapat melihat tombol masuk telah diganti dengan tombol keluar. Anda juga dapat melihat nama pengguna dan penyedia yang dipilih di bawah tombol keluar.
Sekarang setelah Anda memeriksa semuanya bekerja seperti yang diharapkan secara lokal, saatnya untuk menyebarkan perubahan Anda.
Anda dapat menghentikan aplikasi dan API yang sedang berjalan dengan menekan Ctrl-C di kedua terminal.
Menyebarkan perubahan Anda
Di Visual Studio Code, buka palet perintah dengan menekan F1.
Masuk dan pilih Git: Commit All.
Masukkan
Add authentication
sebagai pesan penerapan, dan tekan Enter.Buka palet perintah dengan menekan F1.
Masuk dan pilih Git: Push, dan tekan Enter.
Setelah Anda mendorong perubahan, tunggu hingga proses build dan penerapan berjalan. Perubahan akan terlihat di aplikasi yang Anda sebarkan setelah itu.
Langkah berikutnya
Aplikasi Anda sekarang mendukung autentikasi pengguna dan langkah Anda berikutnya adalah membatasi beberapa bagian aplikasi untuk pengguna yang tidak diautentikasi.