Membuat aplikasi masuk Windows Hello
Ini adalah bagian pertama dari panduan lengkap tentang cara membuat aplikasi Windows paket yang menggunakan Windows Hello sebagai alternatif untuk sistem autentikasi nama pengguna dan kata sandi tradisional. Dalam hal ini, aplikasi ini adalah aplikasi WinUI, tetapi pendekatan yang sama dapat digunakan dengan aplikasi Windows paket apa pun, termasuk WPF dan aplikasi Formulir Windows. Aplikasi ini menggunakan nama pengguna untuk masuk dan membuat kunci Hello untuk setiap akun. Akun-akun ini akan dilindungi oleh PIN yang disiapkan di Pengaturan Windows pada konfigurasi Windows Hello.
Panduan ini dibagi menjadi dua bagian: membangun aplikasi dan menghubungkan layanan backend. Setelah selesai dengan artikel ini, lanjutkan ke Bagian 2: Layanan masuk Windows Hello.
Sebelum memulai, Anda harus membaca ringkasan Windows Hello untuk pemahaman umum tentang cara kerja Windows Hello.
Memulai
Untuk membangun proyek ini, Anda memerlukan pengalaman dengan C#, dan XAML. Anda juga harus menggunakan Visual Studio 2022 pada komputer Windows 10 atau Windows 11. Lihat Mulai menggunakan WinUI untuk instruksi lengkap tentang menyiapkan lingkungan pengembangan Anda.
- Di Visual Studio, pilih File>Baru>Proyek.
- Di filter drop-down dialog Proyek Baru, pilih C#/C++, Windows, dan WinUI.
- Pilih Aplikasi Kosong, Dipaketkan (WinUI 3 di Desktop) dan beri nama aplikasi Anda "WindowsHelloLogin".
- Bangun dan Jalankan aplikasi baru (F5), Anda akan melihat jendela kosong yang ditampilkan di layar. Tutup aplikasi.
Latihan 1: Masuk dengan Windows Hello
Dalam latihan ini Anda akan mempelajari cara memeriksa apakah Windows Hello disiapkan pada komputer, dan cara masuk ke akun menggunakan Windows Hello.
Dalam proyek baru, buat folder baru dalam solusi yang disebut "Views". Folder ini akan berisi halaman yang akan dinavigasi dalam sampel ini. Klik kanan proyek di Penjelajah Solusi, pilih Tambahkan>Folder Baru, lalu ganti nama folder menjadi Tampilan.
Buka MainWindow.xaml dan ganti
Window
konten dengan kosongStackPanel
atauGrid
kontrol. Kami akan menerapkan navigasi halaman dan menavigasi ke halaman baru ketika MainWindow dimuat, jadi kami tidak memerlukan konten apa pun di MainWindow.Title
Tambahkan properti ke MainWindow di XAML. Atribut akan terlihat seperti ini:Title="Windows Hello Login"
.Hapus penanganan aktivitas myButton_Click dari MainWindow.xaml.cs untuk menghindari kesalahan kompilasi. Penanganan aktivitas ini tidak diperlukan untuk sampel ini.
Klik kanan folder Tampilan baru, pilih Tambahkan>Item Baru dan pilih templat Halaman Kosong. Beri nama halaman ini "MainPage.xaml".
Buka file App.xaml.cs dan perbarui handler OnLaunched untuk menerapkan navigasi halaman untuk aplikasi. Anda juga perlu menambahkan metode handler RootFrame_NavigationFailed untuk menangani kesalahan apa pun yang terjadi saat memuat halaman.
protected override void OnLaunched(Microsoft.UI.Xaml.LaunchActivatedEventArgs args) { m_window = new MainWindow(); var rootFrame = new Frame(); rootFrame.NavigationFailed += RootFrame_NavigationFailed; rootFrame.Navigate(typeof(MainPage), args); m_window.Content = rootFrame; m_window.Activate(); } private void RootFrame_NavigationFailed(object sender, NavigationFailedEventArgs e) { throw new Exception($"Error loading page {e.SourcePageType.FullName}"); }
Anda juga harus menambahkan empat pernyataan menggunakan ke bagian atas file App.xaml.cs untuk mengatasi kesalahan kompilasi dalam kode.
using Microsoft.UI.Xaml.Controls; using Microsoft.UI.Xaml.Navigation; using System; using WindowsHelloLogin.Views;
Klik kanan folder Tampilan baru, pilih Tambahkan>Item Baru dan pilih templat Halaman Kosong. Beri nama halaman ini "Login.xaml".
Untuk menentukan antarmuka pengguna untuk halaman masuk baru, tambahkan XAML berikut. XAML ini mendefinisikan
StackPanel
untuk menyelaraskan anak-anak berikut:Yang
TextBlock
akan berisi judul.untuk
TextBlock
pesan kesalahan.A
TextBox
untuk nama pengguna yang akan dimasukkan.Button
untuk menavigasi ke halaman register.untuk
TextBlock
memuat status Windows Hello.TextBlock
Untuk menjelaskan halaman Masuk, karena belum ada backend atau pengguna yang dikonfigurasi.<Grid> <StackPanel> <TextBlock Text="Login" FontSize="36" Margin="4" TextAlignment="Center"/> <TextBlock x:Name="ErrorMessage" Text="" FontSize="20" Margin="4" Foreground="Red" TextAlignment="Center"/> <TextBlock Text="Enter your username below" Margin="0,0,0,20" TextWrapping="Wrap" Width="300" TextAlignment="Center" VerticalAlignment="Center" FontSize="16"/> <TextBox x:Name="UsernameTextBox" Margin="4" Width="250"/> <Button x:Name="LoginButton" Content="Login" Background="DodgerBlue" Foreground="White" Click="LoginButton_Click" Width="80" HorizontalAlignment="Center" Margin="0,20"/> <TextBlock Text="Don't have an account?" TextAlignment="Center" VerticalAlignment="Center" FontSize="16"/> <TextBlock x:Name="RegisterButtonTextBlock" Text="Register now" PointerPressed="RegisterButtonTextBlock_OnPointerPressed" Foreground="DodgerBlue" TextAlignment="Center" VerticalAlignment="Center" FontSize="16"/> <Border x:Name="WindowsHelloStatus" Background="#22B14C" Margin="0,20" Height="100" > <TextBlock x:Name="WindowsHelloStatusText" Text="Windows Hello is ready to use!" Margin="4" TextAlignment="Center" VerticalAlignment="Center" FontSize="20"/> </Border> <TextBlock x:Name="LoginExplanation" FontSize="24" TextAlignment="Center" TextWrapping="Wrap" Text="Please Note: To demonstrate a login, validation will only occur using the default username 'sampleUsername'"/> </StackPanel> </Grid>
Beberapa metode perlu ditambahkan ke file code-behind untuk mendapatkan bangunan solusi. Tekan F7 atau gunakan Penjelajah Solusi untuk mengedit file Login.xaml.cs. Tambahkan dalam dua metode peristiwa berikut untuk menangani peristiwa Masuk dan Daftar . Untuk saat ini metode ini akan mengatur
ErrorMessage.Text
ke string kosong. Pastikan untuk menyertakan pernyataan penggunaan berikut. Mereka akan diperlukan untuk langkah-langkah berikutnya.using Microsoft.UI.Xaml; using Microsoft.UI.Xaml.Controls; using Microsoft.UI.Xaml.Input; using Microsoft.UI.Xaml.Media; using Microsoft.UI.Xaml.Navigation; using System; namespace WindowsHelloLogin.Views { public sealed partial class Login : Page { public Login() { this.InitializeComponent(); } private void LoginButton_Click(object sender, RoutedEventArgs e) { ErrorMessage.Text = ""; } private void RegisterButtonTextBlock_OnPointerPressed(object sender, PointerRoutedEventArgs e) { ErrorMessage.Text = ""; } } }
Untuk merender halaman Masuk , edit kode MainPage untuk menavigasi ke halaman Masuk saat MainPage dimuat. Buka file MainPage.xaml.cs. Di Penjelajah Solusi, klik dua kali pada MainPage.xaml.cs. Jika Anda tidak dapat menemukannya, klik panah kecil di samping MainPage.xaml untuk menampilkan file code-behind. Buat metode penanganan aktivitas yang dimuat yang akan menavigasi ke halaman Masuk .
namespace WindowsHelloLogin.Views { public sealed partial class MainPage : Page { public MainPage() { this.InitializeComponent(); Loaded += MainPage_Loaded; } private void MainPage_Loaded(object sender, RoutedEventArgs e) { Frame.Navigate(typeof(Login)); } } }
Di halaman Masuk , Anda perlu menangani
OnNavigatedTo
peristiwa untuk memvalidasi apakah Windows Hello tersedia di komputer saat ini. Dalam Login.xaml.cs, terapkan kode berikut. Anda akan melihat bahwa objek WindowsHelloHelper menunjukkan bahwa ada kesalahan. Itu karena kita belum membuat kelas pembantu ini.public sealed partial class Login : Page { public Login() { this.InitializeComponent(); } protected override async void OnNavigatedTo(NavigationEventArgs e) { // Check if Windows Hello is set up and available on this machine if (await WindowsHelloHelper.WindowsHelloAvailableCheckAsync()) { } else { // Windows Hello isn't set up, so inform the user WindowsHelloStatus.Background = new SolidColorBrush(Windows.UI.Color.FromArgb(255, 50, 170, 207)); WindowsHelloStatusText.Text = $"Windows Hello is not set up!{Environment.NewLine}Please go to Windows Settings and set up a PIN to use it."; LoginButton.IsEnabled = false; } } }
Untuk membuat kelas WindowsHelloHelper, klik kanan proyek WindowsHelloLogin dan klik Tambahkan>Folder Baru. Beri nama folder ini Utils.
Klik kanan folder Utils dan pilih Tambahkan>Kelas. Beri nama kelas baru ini "WindowsHelloHelper.cs".
Ubah cakupan kelas WindowsHelloHelper menjadi
public static
, lalu tambahkan metode berikut yang untuk memberi tahu pengguna apakah Windows Hello siap digunakan atau tidak. Anda harus menambahkan namespace yang diperlukan.using System; using System.Diagnostics; using System.Threading.Tasks; using Windows.Security.Credentials; namespace WindowsHelloLogin.Utils { public static class WindowsHelloHelper { /// <summary> /// Checks to see if Windows Hello is ready to be used. /// /// Windows Hello has dependencies on: /// 1. Having a connected Microsoft Account /// 2. Having a Windows PIN set up for that account on the local machine /// </summary> public static async Task<bool> WindowsHelloAvailableCheckAsync() { bool keyCredentialAvailable = await KeyCredentialManager.IsSupportedAsync(); if (keyCredentialAvailable == false) { // Key credential is not enabled yet as user // needs to connect to a Microsoft Account and select a PIN in the connecting flow. Debug.WriteLine("Windows Hello is not set up!\nPlease go to Windows Settings and set up a PIN to use it."); return false; } return true; } } }
Di Login.xaml.cs, tambahkan referensi ke
WindowsHelloLogin.Utils
namespace. Ini akan mengatasi kesalahan dalamOnNavigatedTo
metode .using WindowsHelloLogin.Utils;
Membuat dan menjalankan aplikasi. Anda akan dinavigasi ke halaman masuk dan banner Windows Hello akan menunjukkan kepada Anda jika Windows Hello siap digunakan. Anda akan melihat banner hijau atau biru yang menunjukkan status Windows Hello pada komputer Anda.
Hal selanjutnya yang perlu Anda lakukan adalah membangun logika untuk masuk. Buat folder baru dalam proyek bernama "Model".
Di folder Model, buat kelas baru yang disebut "Account.cs". Kelas ini akan bertindak sebagai model akun Anda. Karena ini adalah proyek sampel, ini hanya akan berisi nama pengguna. Ubah cakupan kelas menjadi
public
dan tambahkanUsername
properti .namespace WindowsHelloLogin.Models { public class Account { public string Username { get; set; } } }
Aplikasi ini membutuhkan cara untuk menangani akun. Untuk tangan ini di lab, karena tidak ada server atau database, daftar pengguna disimpan dan dimuat secara lokal. Klik kanan folder Utils dan tambahkan kelas baru bernama "AccountHelper.cs". Ubah cakupan kelas menjadi
public static
. AccountHelper adalah kelas statis yang berisi semua metode yang diperlukan untuk menyimpan dan memuat daftar akun secara lokal. Menyimpan dan memuat pekerjaan dengan menggunakan XmlSerializer. Anda juga perlu mengingat file yang disimpan dan di mana Anda menyimpannya.using System; using System.Collections.Generic; using System.IO; using System.Text; using System.Threading.Tasks; using System.Xml.Serialization; using Windows.Storage; using WindowsHelloLogin.Models; namespace WindowsHelloLogin.Utils { public static class AccountHelper { // In the real world this would not be needed as there would be a server implemented that would host a user account database. // For this tutorial we will just be storing accounts locally. private const string USER_ACCOUNT_LIST_FILE_NAME = "accountlist.txt"; private static string _accountListPath = Path.Combine(ApplicationData.Current.LocalFolder.Path, USER_ACCOUNT_LIST_FILE_NAME); public static List<Account> AccountList = []; /// <summary> /// Create and save a useraccount list file. (Updating the old one) /// </summary> private static async void SaveAccountListAsync() { string accountsXml = SerializeAccountListToXml(); if (File.Exists(_accountListPath)) { StorageFile accountsFile = await StorageFile.GetFileFromPathAsync(_accountListPath); await FileIO.WriteTextAsync(accountsFile, accountsXml); } else { StorageFile accountsFile = await ApplicationData.Current.LocalFolder.CreateFileAsync(USER_ACCOUNT_LIST_FILE_NAME); await FileIO.WriteTextAsync(accountsFile, accountsXml); } } /// <summary> /// Gets the useraccount list file and deserializes it from XML to a list of useraccount objects. /// </summary> /// <returns>List of useraccount objects</returns> public static async Task<List<Account>> LoadAccountListAsync() { if (File.Exists(_accountListPath)) { StorageFile accountsFile = await StorageFile.GetFileFromPathAsync(_accountListPath); string accountsXml = await FileIO.ReadTextAsync(accountsFile); DeserializeXmlToAccountList(accountsXml); } return AccountList; } /// <summary> /// Uses the local list of accounts and returns an XML formatted string representing the list /// </summary> /// <returns>XML formatted list of accounts</returns> public static string SerializeAccountListToXml() { var xmlizer = new XmlSerializer(typeof(List<Account>)); var writer = new StringWriter(); xmlizer.Serialize(writer, AccountList); return writer.ToString(); } /// <summary> /// Takes an XML formatted string representing a list of accounts and returns a list object of accounts /// </summary> /// <param name="listAsXml">XML formatted list of accounts</param> /// <returns>List object of accounts</returns> public static List<Account> DeserializeXmlToAccountList(string listAsXml) { var xmlizer = new XmlSerializer(typeof(List<Account>)); TextReader textreader = new StreamReader(new MemoryStream(Encoding.UTF8.GetBytes(listAsXml))); return AccountList = (xmlizer.Deserialize(textreader)) as List<Account>; } } }
Selanjutnya, terapkan cara untuk menambahkan dan menghapus akun dari daftar akun lokal. Tindakan ini masing-masing akan menyimpan daftar. Metode akhir yang Anda perlukan untuk lab langsung ini adalah metode validasi. Karena tidak ada server otorisasi atau database pengguna, ini akan memvalidasi terhadap satu pengguna yang dikodekan secara permanen. Metode ini harus ditambahkan ke kelas AccountHelper .
public static Account AddAccount(string username) { // Create a new account with the username var account = new Account() { Username = username }; // Add it to the local list of accounts AccountList.Add(account); // SaveAccountList and return the account SaveAccountListAsync(); return account; } public static void RemoveAccount(Account account) { // Remove the account from the accounts list AccountList.Remove(account); // Re save the updated list SaveAccountListAsync(); } public static bool ValidateAccountCredentials(string username) { // In the real world, this method would call the server to authenticate that the account exists and is valid. // However, for this tutorial, we'll just have an existing sample user that's named "sampleUsername". // If the username is null or does not match "sampleUsername" validation will fail. // In this case, the user should register a new Windows Hello user. if (string.IsNullOrEmpty(username)) { return false; } if (!string.Equals(username, "sampleUsername")) { return false; } return true; }
Hal berikutnya yang perlu Anda lakukan adalah menangani permintaan masuk dari pengguna. Di Login.xaml.cs, buat variabel privat baru yang akan menahan masuk akun saat ini. Kemudian tambahkan metode baru bernama SignInWindowsHelloAsync. Ini akan memvalidasi kredensial akun menggunakan metode AccountHelper.ValidateAccountCredentials . Metode ini akan mengembalikan nilai Boolean jika nama pengguna yang dimasukkan sama dengan nilai string berkode keras yang Anda konfigurasikan di langkah sebelumnya. Nilai yang dikodekan secara permanen untuk sampel ini adalah "sampleUsername".
using WindowsHelloLogin.Models; using WindowsHelloLogin.Utils; using System.Diagnostics; using System.Threading.Tasks; namespace WindowsHelloLogin.Views { public sealed partial class Login : Page { private Account _account; public Login() { this.InitializeComponent(); } protected override async void OnNavigatedTo(NavigationEventArgs e) { // Check if Windows Hello is set up and available on this machine if (await WindowsHelloHelper.WindowsHelloAvailableCheckAsync()) { } else { // Windows Hello is not set up, so inform the user WindowsHelloStatus.Background = new SolidColorBrush(Windows.UI.Color.FromArgb(255, 50, 170, 207)); WindowsHelloStatusText.Text = "Windows Hello is not set up!\nPlease go to Windows Settings and set up a PIN to use it."; LoginButton.IsEnabled = false; } } private async void LoginButton_Click(object sender, RoutedEventArgs e) { ErrorMessage.Text = ""; await SignInWindowsHelloAsync(); } private void RegisterButtonTextBlock_OnPointerPressed(object sender, PointerRoutedEventArgs e) { ErrorMessage.Text = ""; } private async Task SignInWindowsHelloAsync() { if (AccountHelper.ValidateAccountCredentials(UsernameTextBox.Text)) { // Create and add a new local account _account = AccountHelper.AddAccount(UsernameTextBox.Text); Debug.WriteLine("Successfully signed in with traditional credentials and created local account instance!"); //if (await WindowsHelloHelper.CreateWindowsHelloKeyAsync(UsernameTextBox.Text)) //{ // Debug.WriteLine("Successfully signed in with Windows Hello!"); //} } else { ErrorMessage.Text = "Invalid Credentials"; } } } }
Anda mungkin telah melihat kode yang dikomentari yang merujuk metode di WindowsHelloHelper. Di WindowsHelloHelper.cs, tambahkan metode baru bernama CreateWindowsHelloKeyAsync. Metode ini menggunakan Windows Hello API di KeyCredentialManager. Memanggil RequestCreateAsync akan membuat kunci Windows Hello yang khusus untuk accountId dan komputer lokal. Harap perhatikan komentar dalam pernyataan switch jika Anda tertarik untuk menerapkan ini dalam skenario dunia nyata.
/// <summary> /// Creates a Windows Hello key on the machine using the account ID provided. /// </summary> /// <param name="accountId">The account ID associated with the account that we are enrolling into Windows Hello</param> /// <returns>Boolean indicating if creating the Windows Hello key succeeded</returns> public static async Task<bool> CreateWindowsHelloKeyAsync(string accountId) { KeyCredentialRetrievalResult keyCreationResult = await KeyCredentialManager.RequestCreateAsync(accountId, KeyCredentialCreationOption.ReplaceExisting); switch (keyCreationResult.Status) { case KeyCredentialStatus.Success: Debug.WriteLine("Successfully created key"); // In the real world, authentication would take place on a server. // So, every time a user migrates or creates a new Windows Hello // account, details should be pushed to the server. // The details that would be pushed to the server include: // The public key, keyAttestation (if available), // certificate chain for attestation endorsement key (if available), // status code of key attestation result: keyAttestationIncluded or // keyAttestationCanBeRetrievedLater and keyAttestationRetryType. // As this sample has no concept of a server, it will be skipped for now. // For information on how to do this, refer to the second sample. // For this sample, just return true return true; case KeyCredentialStatus.UserCanceled: Debug.WriteLine("User cancelled sign-in process."); break; case KeyCredentialStatus.NotFound: // User needs to set up Windows Hello Debug.WriteLine("Windows Hello is not set up!\nPlease go to Windows Settings and set up a PIN to use it."); break; default: break; } return false; }
Sekarang setelah Anda membuat metode CreateWindowsHelloKeyAsync , kembali ke file Login.xaml.cs dan batalkan komentar kode di dalam metode SignInWindowsHelloAsync.
private async void SignInWindowsHelloAsync() { if (AccountHelper.ValidateAccountCredentials(UsernameTextBox.Text)) { //Create and add a new local account _account = AccountHelper.AddAccount(UsernameTextBox.Text); Debug.WriteLine("Successfully signed in with traditional credentials and created local account instance!"); if (await WindowsHelloHelper.CreateWindowsHelloKeyAsync(UsernameTextBox.Text)) { Debug.WriteLine("Successfully signed in with Windows Hello!"); } } else { ErrorMessage.Text = "Invalid Credentials"; } }
Membuat dan menjalankan aplikasi. Anda akan dibawa ke halaman Masuk. Masukkan nama pengguna sebagai "sampleUsername" dan klik masuk. Anda akan diminta dengan permintaan Windows Hello yang meminta Anda untuk memasukkan PIN Anda. Setelah memasukkan PIN Anda dengan benar, metode CreateWindowsHelloKeyAsync akan dapat membuat kunci Windows Hello. Pantau jendela output untuk melihat apakah pesan yang menunjukkan keberhasilan ditampilkan.
Latihan 2: Halaman Selamat Datang dan Pilihan Pengguna
Dalam latihan ini, Anda akan melanjutkan dari latihan sebelumnya. Ketika pengguna berhasil masuk, mereka harus dibawa ke halaman selamat datang di mana mereka dapat keluar atau menghapus akun mereka. Saat Windows Hello membuat kunci untuk setiap komputer, layar pilihan pengguna dapat dibuat, yang menampilkan semua pengguna yang telah masuk pada komputer tersebut. Pengguna kemudian dapat memilih salah satu akun ini dan langsung masuk ke layar selamat datang tanpa perlu memasukkan kembali kata sandi karena mereka telah mengautentikasi untuk mengakses komputer.
Di folder Tampilan tambahkan halaman kosong baru bernama "Welcome.xaml". Tambahkan XAML berikut untuk menyelesaikan antarmuka pengguna untuk halaman. Ini akan menampilkan judul, nama pengguna yang masuk, dan dua tombol. Salah satu tombol akan menavigasi kembali ke daftar pengguna (yang akan Anda buat nanti), dan tombol lainnya akan menangani melupakan pengguna ini.
<Grid> <StackPanel> <TextBlock x:Name="Title" Text="Welcome" FontSize="40" TextAlignment="Center"/> <TextBlock x:Name="UserNameText" FontSize="28" TextAlignment="Center"/> <Button x:Name="BackToUserListButton" Content="Back to User List" Click="Button_Restart_Click" HorizontalAlignment="Center" Margin="0,20" Foreground="White" Background="DodgerBlue"/> <Button x:Name="ForgetButton" Content="Forget Me" Click="Button_Forget_User_Click" Foreground="White" Background="Gray" HorizontalAlignment="Center"/> </StackPanel> </Grid>
Dalam file Welcome.xaml.cs code-behind, tambahkan variabel privat baru yang akan menahan akun yang masuk. Anda harus menerapkan metode untuk mengambil
OnNavigateTo
alih acara, ini akan menyimpan akun yang diteruskan ke halaman Selamat Datang . Anda juga perlu mengimplementasikanClick
peristiwa untuk dua tombol yang ditentukan dalam XAML. Anda perlu menambahkan menggunakan pernyataan untukWindowsHelloLogin.Models
namespace layanan danWindowsHelloLogin.Utils
.using WindowsHelloLogin.Models; using WindowsHelloLogin.Utils; using System.Diagnostics; namespace WindowsHelloLogin.Views { public sealed partial class Welcome : Page { private Account _activeAccount; public Welcome() { InitializeComponent(); } protected override void OnNavigatedTo(NavigationEventArgs e) { _activeAccount = (Account)e.Parameter; if (_activeAccount != null) { UserNameText.Text = _activeAccount.Username; } } private void Button_Restart_Click(object sender, RoutedEventArgs e) { } private void Button_Forget_User_Click(object sender, RoutedEventArgs e) { // Remove the account from Windows Hello // WindowsHelloHelper.RemoveWindowsHelloAccountAsync(_activeAccount); // Remove it from the local accounts list and re-save the updated list AccountHelper.RemoveAccount(_activeAccount); Debug.WriteLine($"User {_activeAccount.Username} deleted."); } } }
Anda mungkin telah melihat baris yang dikomentari di
Button_Forget_User_Click
penanganan aktivitas. Akun sedang dihapus dari daftar lokal Anda tetapi saat ini tidak ada cara untuk dihapus dari Windows Hello. Anda perlu menerapkan metode baru di WindowsHelloHelper.cs yang akan menangani penghapusan pengguna Windows Hello. Metode ini akan menggunakan API Windows Hello lainnya untuk membuka dan menghapus akun. Di dunia nyata, ketika Anda menghapus akun, server atau database harus diberi tahu sehingga database pengguna tetap valid. Anda akan memerlukan pernyataan penggunaan yang mereferensikanWindowsHelloLogin.Models
namespace.using WindowsHelloLogin.Models; /// <summary> /// Function to be called when user requests deleting their account. /// Checks the KeyCredentialManager to see if there is a Windows Hello /// account for the current user. /// It then deletes the local key associated with the account. /// </summary> public static async void RemoveWindowsHelloAccountAsync(Account account) { // Open the account with Windows Hello KeyCredentialRetrievalResult keyOpenResult = await KeyCredentialManager.OpenAsync(account.Username); if (keyOpenResult.Status == KeyCredentialStatus.Success) { // In the real world you would send key information to server to unregister //for example, RemoveWindowsHelloAccountOnServer(account); } // Then delete the account from the machine's list of Windows Hello accounts await KeyCredentialManager.DeleteAsync(account.Username); }
Kembali ke Welcome.xaml.cs, batalkan komentar baris yang memanggil RemoveWindowsHelloAccountAsync.
private void Button_Forget_User_Click(object sender, RoutedEventArgs e) { // Remove it from Windows Hello WindowsHelloHelper.RemoveWindowsHelloAccountAsync(_activeAccount); // Remove it from the local accounts list and re-save the updated list AccountHelper.RemoveAccount(_activeAccount); Debug.WriteLine($"User {_activeAccount.Username} deleted."); }
Dalam metode SignInWindowsHelloAsync (dalam Login.xaml.cs), setelah CreateWindowsHelloKeyAsync berhasil, itu harus menavigasi ke halaman Selamat Datang dan meneruskan Akun.
private async void SignInWindowsHelloAsync() { if (AccountHelper.ValidateAccountCredentials(UsernameTextBox.Text)) { // Create and add a new local account _account = AccountHelper.AddAccount(UsernameTextBox.Text); Debug.WriteLine("Successfully signed in with traditional credentials and created local account instance!"); if (await WindowsHelloHelper.CreateWindowsHelloKeyAsync(UsernameTextBox.Text)) { Debug.WriteLine("Successfully signed in with Windows Hello!"); Frame.Navigate(typeof(Welcome), _account); } } else { ErrorMessage.Text = "Invalid Credentials"; } }
Membuat dan menjalankan aplikasi. Masuk dengan "sampleUsername" dan klik Masuk. Masukkan PIN Anda dan jika berhasil, Anda harus dinavigasi ke layar Selamat Datang . Coba klik Lupakan Pengguna dan pantau jendela Output Visual Studio untuk melihat apakah pengguna telah dihapus. Perhatikan bahwa ketika pengguna dihapus, Anda tetap berada di halaman Selamat Datang . Anda harus membuat halaman pilihan pengguna yang dapat dinavigasi aplikasi.
Di folder Tampilan, buat halaman kosong baru bernama "UserSelection.xaml" dan tambahkan XAML berikut untuk menentukan antarmuka pengguna. Halaman ini akan berisi ListView yang menampilkan semua pengguna dalam daftar akun lokal, dan
Button
yang akan menavigasi ke halaman Masuk untuk memungkinkan pengguna menambahkan akun lain.<Grid> <StackPanel> <TextBlock x:Name="Title" Text="Select a User" FontSize="36" Margin="4" TextAlignment="Center" HorizontalAlignment="Center"/> <ListView x:Name="UserListView" Margin="4" MaxHeight="200" MinWidth="250" Width="250" HorizontalAlignment="Center"> <ListView.ItemTemplate> <DataTemplate> <Grid Background="DodgerBlue" Height="50" Width="250" HorizontalAlignment="Stretch" VerticalAlignment="Stretch"> <TextBlock Text="{Binding Username}" HorizontalAlignment="Center" TextAlignment="Center" VerticalAlignment="Center" Foreground="White"/> </Grid> </DataTemplate> </ListView.ItemTemplate> </ListView> <Button x:Name="AddUserButton" Content="+" FontSize="36" Width="60" Click="AddUserButton_Click" HorizontalAlignment="Center"/> </StackPanel> </Grid>
Di UserSelection.xaml.cs, terapkan
Loaded
metode yang akan menavigasi ke halaman Masuk jika tidak ada akun dalam daftar lokal. Terapkan jugaSelectionChanged
acara untukListView
danClick
acara untukButton
.using System.Diagnostics; using WindowsHelloLogin.Models; using WindowsHelloLogin.Utils; namespace WindowsHelloLogin.Views { public sealed partial class UserSelection : Page { public UserSelection() { InitializeComponent(); Loaded += UserSelection_Loaded; } private void UserSelection_Loaded(object sender, RoutedEventArgs e) { if (AccountHelper.AccountList.Count == 0) { // If there are no accounts, navigate to the Login page Frame.Navigate(typeof(Login)); } UserListView.ItemsSource = AccountHelper.AccountList; UserListView.SelectionChanged += UserSelectionChanged; } /// <summary> /// Function called when an account is selected in the list of accounts /// Navigates to the Login page and passes the chosen account /// </summary> private void UserSelectionChanged(object sender, RoutedEventArgs e) { if (((ListView)sender).SelectedValue != null) { Account account = (Account)((ListView)sender).SelectedValue; if (account != null) { Debug.WriteLine($"Account {account.Username} selected!"); } Frame.Navigate(typeof(Login), account); } } /// <summary> /// Function called when the "+" button is clicked to add a new user. /// Navigates to the Login page with nothing filled out /// </summary> private void AddUserButton_Click(object sender, RoutedEventArgs e) { Frame.Navigate(typeof(Login)); } } }
Ada beberapa tempat di aplikasi tempat Anda ingin menavigasi ke halaman UserSelection . Di MainPage.xaml.cs, Anda harus menavigasi ke halaman UserSelection alih-alih halaman Masuk . Saat Anda berada dalam peristiwa yang dimuat di MainPage, Anda harus memuat daftar akun sehingga halaman UserSelection dapat memeriksa apakah ada akun. Ini akan mengharuskan
Loaded
mengubah metode menjadi asinkron dan juga menambahkan pernyataan penggunaan untukWindowsHelloLogin.Utils
namespace.using WindowsHelloLogin.Utils; private async void MainPage_Loaded(object sender, RoutedEventArgs e) { // Load the local account list before navigating to the UserSelection page await AccountHelper.LoadAccountListAsync(); Frame.Navigate(typeof(UserSelection)); }
Selanjutnya, aplikasi perlu menavigasi ke halaman UserSelection dari halaman Selamat Datang . Di kedua
Click
peristiwa, Anda harus menavigasi kembali ke halaman UserSelection .private void Button_Restart_Click(object sender, RoutedEventArgs e) { Frame.Navigate(typeof(UserSelection)); } private void Button_Forget_User_Click(object sender, RoutedEventArgs e) { // Remove it from Windows Hello WindowsHelloHelper.RemoveWindowsHelloAccountAsync(_activeAccount); // Remove it from the local accounts list and re-save the updated list AccountHelper.RemoveAccount(_activeAccount); Debug.WriteLine($"User {_activeAccount.Username} deleted."); // Navigate back to UserSelection page. Frame.Navigate(typeof(UserSelection)); }
Di halaman Masuk , Anda memerlukan kode untuk masuk ke akun yang dipilih dari daftar di halaman UserSelection . Dalam peristiwa tersebut
OnNavigatedTo
, simpan akun yang diteruskan selama navigasi. Mulailah dengan menambahkan variabel privat baru yang akan mengidentifikasi apakah akun tersebut adalah akun yang sudah ada. Kemudian tanganiOnNavigatedTo
peristiwa.namespace WindowsHelloLogin.Views { public sealed partial class Login : Page { private Account _account; private bool _isExistingAccount; public Login() { InitializeComponent(); } /// <summary> /// Function called when this frame is navigated to. /// Checks to see if Windows Hello is available and if an account was passed in. /// If an account was passed in set the "_isExistingAccount" flag to true and set the _account. /// </summary> protected override async void OnNavigatedTo(NavigationEventArgs e) { // Check Windows Hello is set up and available on this machine if (await WindowsHelloHelper.WindowsHelloAvailableCheckAsync()) { if (e.Parameter != null) { _isExistingAccount = true; // Set the account to the existing account being passed in _account = (Account)e.Parameter; UsernameTextBox.Text = _account.Username; await SignInWindowsHelloAsync(); } } else { // Windows Hello is not set up, so inform the user WindowsHelloStatus.Background = new SolidColorBrush(Windows.UI.Color.FromArgb(255, 50, 170, 207)); WindowsHelloStatusText.Text = $"Windows Hello is not set up!{Environment.NewLine}Please go to Windows Settings and set up a PIN to use it."; LoginButton.IsEnabled = false; } } } }
Metode SignInWindowsHelloAsync perlu diperbarui untuk masuk ke akun yang dipilih. WindowsHelloHelper akan memerlukan metode lain untuk membuka akun dengan Windows Hello, karena akun sudah memiliki kunci akun yang dibuat untuknya. Terapkan metode baru di WindowsHelloHelper.cs untuk memasukkan pengguna yang sudah ada dengan Windows Hello. Untuk informasi tentang setiap bagian kode, silakan baca komentar kode.
/// <summary> /// Attempts to sign a message using the account key on the system for the accountId passed. /// </summary> /// <returns>Boolean representing if creating the Windows Hello authentication message succeeded</returns> public static async Task<bool> GetWindowsHelloAuthenticationMessageAsync(Account account) { KeyCredentialRetrievalResult openKeyResult = await KeyCredentialManager.OpenAsync(account.Username); // Calling OpenAsync will allow the user access to what is available in the app and will not require user credentials again. // If you wanted to force the user to sign in again you can use the following: // var consentResult = await Windows.Security.Credentials.UI.UserConsentVerifier.RequestVerificationAsync(account.Username); // This will ask for the either the password of the currently signed in Microsoft Account or the PIN used for Windows Hello. if (openKeyResult.Status == KeyCredentialStatus.Success) { // If OpenAsync has succeeded, the next thing to think about is whether the client application requires access to backend services. // If it does here you would request a challenge from the server. The client would sign this challenge and the server // would check the signed challenge. If it is correct, it would allow the user access to the backend. // You would likely make a new method called RequestSignAsync to handle all this. // For example, RequestSignAsync(openKeyResult); // Refer to the second Windows Hello sample for information on how to do this. // For this sample, there is not concept of a server implemented so just return true. return true; } else if (openKeyResult.Status == KeyCredentialStatus.NotFound) { // If the account is not found at this stage. It could be one of two errors. // 1. Windows Hello has been disabled // 2. Windows Hello has been disabled and re-enabled cause the Windows Hello Key to change. // Calling CreateWindowsHelloKeyAsync and passing through the account will attempt to replace the existing Windows Hello Key for that account. // If the error really is that Windows Hello is disabled then the CreateWindowsHelloKeyAsync method will output that error. if (await CreateWindowsHelloKeyAsync(account.Username)) { // If the Hello Key was again successfully created, Windows Hello has just been reset. // Now that the Hello Key has been reset for the account retry sign in. return await GetWindowsHelloAuthenticationMessageAsync(account); } } // Can't use Windows Hello right now, try again later return false; }
Perbarui metode SignInWindowsHelloAsync di Login.xaml.cs untuk menangani akun yang ada. Ini akan menggunakan metode baru dalam WindowsHelloHelper.cs. Jika berhasil, akun akan masuk dan pengguna menavigasi ke halaman Selamat Datang .
private async Task SignInWindowsHelloAsync() { if (_isExistingAccount) { if (await WindowsHelloHelper.GetWindowsHelloAuthenticationMessageAsync(_account)) { Frame.Navigate(typeof(Welcome), _account); } } else if (AccountHelper.ValidateAccountCredentials(UsernameTextBox.Text)) { //Create and add a new local account _account = AccountHelper.AddAccount(UsernameTextBox.Text); Debug.WriteLine("Successfully signed in with traditional credentials and created local account instance!"); if (await WindowsHelloHelper.CreateWindowsHelloKeyAsync(UsernameTextBox.Text)) { Debug.WriteLine("Successfully signed in with Windows Hello!"); Frame.Navigate(typeof(Welcome), _account); } } else { ErrorMessage.Text = "Invalid Credentials"; } }
Membuat dan menjalankan aplikasi. Masuk dengan "sampleUsername". Ketik PIN Anda dan jika berhasil, Anda akan dinavigasi ke halaman Selamat Datang . Klik kembali ke daftar pengguna. Anda sekarang akan melihat pengguna dalam daftar. Jika Anda mengklik ini, WindowsHello memungkinkan Anda untuk masuk kembali tanpa harus memasukkan kembali kata sandi apa pun dll.
Latihan 3: Mendaftarkan pengguna Windows Hello baru
Dalam latihan ini, Anda membuat halaman baru yang dapat membuat akun baru dengan Windows Hello. Ini berfungsi sama dengan cara kerja halaman Masuk . Halaman Masuk diimplementasikan untuk pengguna yang sudah ada yang bermigrasi untuk menggunakan Windows Hello. Halaman WindowsHelloRegister akan membuat pendaftaran Windows Hello untuk pengguna baru.
Di folder Tampilan, buat halaman kosong baru bernama "WindowsHelloRegister.xaml". Di XAML tambahkan hal berikut untuk menyiapkan antarmuka pengguna. Antarmuka di halaman ini mirip dengan halaman Masuk .
<Grid> <StackPanel> <TextBlock x:Name="Title" Text="Register New Windows Hello User" FontSize="24" Margin="4" TextAlignment="Center"/> <TextBlock x:Name="ErrorMessage" Text="" FontSize="20" Margin="4" Foreground="Red" TextAlignment="Center"/> <TextBlock Text="Enter your new username below" Margin="0,0,0,20" TextWrapping="Wrap" Width="300" TextAlignment="Center" VerticalAlignment="Center" FontSize="16"/> <TextBox x:Name="UsernameTextBox" Margin="4" Width="250"/> <Button x:Name="RegisterButton" Content="Register" Background="DodgerBlue" Foreground="White" Click="RegisterButton_Click_Async" Width="80" HorizontalAlignment="Center" Margin="0,20"/> <Border x:Name="WindowsHelloStatus" Background="#22B14C" Margin="4" Height="100"> <TextBlock x:Name="WindowsHelloStatusText" Text="Windows Hello is ready to use!" FontSize="20" Margin="4" TextAlignment="Center" VerticalAlignment="Center"/> </Border> </StackPanel> </Grid>
Dalam file WindowsHelloRegister.xaml.cs code-behind, terapkan variabel privat
Account
danClick
peristiwa untuk tombol daftar. Ini akan menambahkan akun lokal baru dan membuat kunci Windows Hello.using Microsoft.UI.Xaml.Controls; using Microsoft.UI.Xaml; using WindowsHelloLogin.Models; using WindowsHelloLogin.Utils; namespace WindowsHelloLogin.Views { public sealed partial class WindowsHelloRegister : Page { private Account _account; public WindowsHelloRegister() { InitializeComponent(); } private async void RegisterButton_Click_Async(object sender, RoutedEventArgs e) { ErrorMessage.Text = ""; // In the real world, you would validate the entered credentials and information before // allowing a user to register a new account. // For this sample, we'll skip that step and just register an account if the username is not null. if (!string.IsNullOrEmpty(UsernameTextBox.Text)) { // Register a new account _account = AccountHelper.AddAccount(UsernameTextBox.Text); // Register new account with Windows Hello await WindowsHelloHelper.CreateWindowsHelloKeyAsync(_account.Username); // Navigate to the Welcome page. Frame.Navigate(typeof(Welcome), _account); } else { ErrorMessage.Text = "Please enter a username"; } } } }
Anda perlu menavigasi ke halaman ini dari halaman Masuk saat daftar diklik.
private void RegisterButtonTextBlock_OnPointerPressed(object sender, PointerRoutedEventArgs e) { ErrorMessage.Text = ""; Frame.Navigate(typeof(WindowsHelloRegister)); }
Membuat dan menjalankan aplikasi. Coba daftarkan pengguna baru. Kemudian kembali ke daftar pengguna dan validasi bahwa Anda dapat memilih pengguna tersebut dan masuk.
Di lab ini, Anda telah mempelajari keterampilan penting yang diperlukan untuk menggunakan Windows Hello API baru untuk mengautentikasi pengguna yang ada dan membuat akun untuk pengguna baru. Dengan pengetahuan baru ini, Anda dapat mulai menghapus kebutuhan pengguna untuk mengingat kata sandi untuk aplikasi Anda, namun tetap yakin bahwa aplikasi Anda tetap dilindungi oleh autentikasi pengguna. Windows menggunakan teknologi autentikasi baru Windows Hello untuk mendukung opsi masuk biometriknya.
Topik terkait
Windows developer