Megjegyzés
Az oldalhoz való hozzáféréshez engedély szükséges. Megpróbálhat bejelentkezni vagy módosítani a címtárat.
Az oldalhoz való hozzáféréshez engedély szükséges. Megpróbálhatja módosítani a címtárat.
Ez az első része annak a teljes útmutatónak, amely bemutatja, hogyan hozhat létre olyan csomagolt Windows app, amely Windows Hello használ a hagyományos felhasználónév- és jelszó-hitelesítési rendszerek alternatívaként. Ebben az esetben az alkalmazás egy WinUI 3-alkalmazás, de ugyanez a megközelítés használható bármilyen csomagolt Windows app, beleértve a WPF és Windows Forms alkalmazásokat is. Az alkalmazás felhasználónevet használ a bejelentkezéshez, és minden fiókhoz létrehoz egy Hello-kulcsot. Ezeket a fiókokat a Windows Hello konfigurációjára vonatkozó Windows-beállításokban beállított PIN-kód védi.
Ez az útmutató két részre oszlik: az alkalmazás kiépítésére és a háttérszolgáltatás csatlakoztatására. Ha befejezte ezt a cikket, folytassa a 2. résztel: Windows Hello bejelentkezési szolgáltatás.
Mielőtt hozzákezdene, olvassa el a Windows Hello áttekintést a Windows Hello működésének általános megértéséhez.
Első lépések
A project létrehozásához szüksége lesz némi tapasztalatra a C# és az XAML használatával kapcsolatban. A Visual Studio 2026-ot Windows 10 vagy Windows 11 rendszerű gépen is használnia kell. A fejlesztési környezet beállításával kapcsolatos útmutatásért tekintse meg a Windows-alkalmazások fejlesztésének megkezdését ismertető cikket.
- A Visual Studio válassza a File>New>Project lehetőséget.
- A Új Project párbeszédpanel legördülő szűrőiben válassza a C#/C++, Windows és WinUI lehetőséget.
- Válassza a WinUI Blank App (Csomagolt) lehetőséget , és adja az alkalmazásnak a "WindowsHelloLogin" nevet.
- Az új alkalmazás (F5) létrehozása és futtatásakor egy üres ablaknak kell megjelennie a képernyőn. Zárja be az alkalmazást.
1. gyakorlat: Bejelentkezés a Windows Hello-val
Ebben a gyakorlatban megtudhatja, hogyan ellenőrizheti, hogy Windows Hello van-e beállítva a gépen, és hogyan jelentkezhet be egy fiókba Windows Hello használatával.
Az új projektben hozzon létre egy "Nézetek" nevű új mappát a megoldásban. Ez a mappa tartalmazza azokat a lapokat, amelyekre a mintában navigálni fog. Kattintson a jobb gombbal a project a Solution Explorer területen, válassza a Add>Új mappa lehetőséget, majd nevezze át a mappát Nézetek.
Nyissa meg a MainWindow.xaml fájlt, és cserélje le a
Windowtartalmat egy üresStackPanelvagyGridvezérlőre. A MainWindow betöltésekor az oldalnavigációt implementáljuk, és egy új lapra navigálunk, így nincs szükségünk tartalomra a MainWindow-ban.Adjon hozzá egy tulajdonságot
Titlea MainWindow-hoz az XAML-ben. Az attribútumnak így kell kinéznie:Title="Windows Hello Login".Az összeállítási hibák elkerülése érdekében távolítsa el a myButton_Click eseménykezelőt a MainWindow.xaml.cs-ből. Ehhez a mintához nincs szükség eseménykezelőre.
Kattintson a jobb gombbal az új Nézetek mappára, válassza azÚj elem>, majd az Üres lap sablon lehetőséget. Nevezze el ezt az oldalt "MainPage.xaml".
Nyissa meg a App.xaml.cs fájlt, és frissítse az OnLaunched kezelőt az alkalmazás oldalnavigációjának implementálásához. Hozzá kell adnia egy RootFrame_NavigationFailed kezelőmetódust is a lapok betöltése során előforduló hibák kezeléséhez.
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}"); }A kód fordítási hibáinak megoldásához négy utasítást is fel kell vennie a App.xaml.cs fájl tetejére.
using Microsoft.UI.Xaml.Controls; using Microsoft.UI.Xaml.Navigation; using System; using WindowsHelloLogin.Views;Kattintson a jobb gombbal az új Nézetek mappára, válassza azÚj elem>, majd az Üres lap sablon lehetőséget. Nevezze el ezt az oldalt "Login.xaml".
Az új bejelentkezési oldal felhasználói felületének meghatározásához adja hozzá a következő XAML-t. Ez az XAML a
StackPanela következő elemek igazítását határozza meg.Olyan
TextBlock, amely tartalmazni fog egy címet.A
TextBlockhibaüzenetekhez.A
TextBoxa felhasználónév beviteléhez.A
Buttona regisztrációs lapra való navigáláshoz.Egy
TextBlock, amely a(z) Windows Hello állapotát tartalmazza.A
TextBlockbejelentkezési lap magyarázata, mivel még nincsenek háttérbeli vagy konfigurált felhasználók.<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>
A megoldás létrehozásához néhány metódust hozzá kell adni a kód mögötti fájlhoz. Nyomja le az F7 billentyűt, vagy használja a Solution Explorer a Login.xaml.cs fájl szerkesztéséhez. Adja hozzá a következő két eseménymetelyt a bejelentkezési és regisztrációs események kezeléséhez. Egyelőre ezek a metódusok üres sztringre állítják be a
ErrorMessage.Textmetódust. Ügyeljen arra, hogy az alábbi utasításokat használja. A következő lépésekhez szükség lesz rájuk.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 = ""; } } }A Bejelentkezési lap megjelenítéséhez szerkessze a MainPage-kódot, hogy a MainPage betöltésekor a Bejelentkezési lapra navigáljon. Nyissa meg a MainPage.xaml.cs fájlt. Solution Explorer-ben kattintson duplán a MainPage.xaml.cs fájlra. Ha ezt nem találja, kattintson a MainPage.xaml melletti kis nyílra a kód mögötti fájl megjelenítéséhez. Hozzon létre egy betöltött eseménykezelő metódust, amely a Bejelentkezési lapra navigál.
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)); } } }A Login lapon kezelnie kell a
OnNavigatedToeseményt annak ellenőrzéséhez, hogy Windows Hello elérhető-e az aktuális gépen. Az Login.xaml.cs implementálja a következő kódot. Megfigyelheti, hogy a WindowsHelloHelper objektum azt jelzi, hogy hiba történt. Ennek az az oka, hogy még nem hoztuk létre ezt a segédosztályt.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; } } }A WindowsHelloHelper osztály létrehozásához kattintson a jobb gombbal a WindowsHelloLogin project, majd a Add>Új mappa elemre. Nevezze el ezt a mappát Utils néven.
Kattintson a jobb gombbal a Utils mappára, és válassza azOsztály>. Az új osztály neve "WindowsHelloHelper.cs".
Módosítsa a WindowsHelloHelper osztály hatókörét
public static, majd adja hozzá a következő módszert, amely tájékoztatja a felhasználót arról, hogy Windows Hello készen áll-e a használatra. Hozzá kell adnia a szükséges névtereket.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; } } }A Login.xaml.cs adjon hozzá egy hivatkozást a
WindowsHelloLogin.Utilsnévtérhez. Ez megoldja a metódus hibájátOnNavigatedTo.using WindowsHelloLogin.Utils;Hozza létre és futtassa az alkalmazást. Ekkor a bejelentkezési lapra navigál, és a Windows Hello szalagcím jelzi, hogy Windows Hello készen áll-e a használatra. A számítógépén a Windows Hello állapotát jelző zöld vagy kék sávnak kellene megjelennie.
A következő lépés a bejelentkezés logikájának létrehozása. Hozzon létre egy új mappát a "Models" nevű project.
A Modellek mappában hozzon létre egy "Account.cs" nevű új osztályt. Ez az osztály lesz a fiókmodellje. Mivel ez egy minta project, csak egy felhasználónevet fog tartalmazni. Módosítsa az osztály hatókörét,
publicés adja hozzá a tulajdonságotUsername.namespace WindowsHelloLogin.Models { public class Account { public string Username { get; set; } } }Az alkalmazásnak módot kell adni a fiókok kezelésére. Ehhez a tesztkörnyezethez, mivel nincs kiszolgáló vagy adatbázis, a rendszer helyileg menti és betölti a felhasználók listáját. Kattintson a jobb gombbal a Utils mappára, és adjon hozzá egy új osztályt "AccountHelper.cs" néven. Az osztály hatókörét
public staticváltoztatni. Az AccountHelper egy statikus osztály, amely tartalmazza a fiókok helyi mentéséhez és betöltéséhez szükséges összes metódust. A mentés és a betöltés XmlSerializer használatával működik. A mentett fájlra és a mentési helyre is emlékeznie kell.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>; } } }Ezután implementáljon egy módot egy fiók hozzáadására és eltávolítására a helyi fiókok listájából. Ezek a műveletek külön-külön mentik a listát. Az utolsó módszer, amire szüksége van ebben a gyakorlati laborban, egy érvényesítési módszer. Mivel nincs engedélyezési kiszolgáló vagy a felhasználók adatbázisa, ez egyetlen, szigorúan kódolt felhasználón lesz érvényesítve. Ezeket a metódusokat hozzá kell adni az AccountHelper osztályhoz.
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; }A következő lépés a felhasználó bejelentkezési kérésének kezelése. A Login.xaml.cs hozzon létre egy új privát változót, amely az aktuális fiók bejelentkezését fogja tárolni. Ezután adjon hozzá egy új, SignInWindowsHelloAsync nevű metódust. Ez az AccountHelper.ValidateAccountCredentials metódussal ellenőrzi a fiók hitelesítő adatait. Ez a metódus logikai értéket ad vissza, ha a megadott felhasználónév megegyezik az előző lépésben konfigurált, kemény kóddal megadott sztringértékel. A minta hard-coded értéke "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"; } } } }Előfordulhat, hogy észrevette a Megjegyzés kódot, amely egy metódusra hivatkozik a WindowsHelloHelperben. A WindowsHelloHelper.cs adjon hozzá egy új, CreateWindowsHelloKeyAsync nevű metódust. Ez a metódus a KeyCredentialManager Windows Hello API-t használja. A RequestCreateAsync hívása létrehoz egy Windows Hello kulcsot, amely a accountId és a helyi gépre jellemző. Amennyiben érdeklődik a valós világban történő megvalósítás iránt, vegye figyelembe a switch utasításban szereplő megjegyzéseket.
/// <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; }Most, hogy létrehozta a CreateWindowsHelloKeyAsync metódust, térjen vissza a Login.xaml.cs fájlhoz, és oldja fel a kódot a SignInWindowsHelloAsync metódusban.
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"; } }Hozza létre és futtassa az alkalmazást. A Bejelentkezési oldalra lesz irányítva. Adja meg a felhasználónevet "sampleUsername" névként, és kattintson a bejelentkezésre. A rendszer megjelenít egy Windows Hello üzenetet, amely arra kéri, hogy adja meg a PIN-kódját. A PIN-kód helyes megadása után a CreateWindowsHelloKeyAsync metódus létrehozhat egy Windows Hello kulcsot. Figyelje meg a kimeneti ablakokat, hogy megjelenjenek-e a sikerességet jelző üzenetek.
2. gyakorlat: Üdvözlő- és felhasználói kijelölési lapok
Ebben a gyakorlatban Ön folytatja az előző gyakorlatot. Amikor egy felhasználó sikeresen bejelentkezik, egy üdvözlőoldalra kell vinni, ahol kijelentkezhet vagy törölheti a fiókját. Mivel Windows Hello minden géphez létrehoz egy kulcsot, létre lehet hozni egy felhasználóválasztó képernyőt, amely megjeleníti a gépen bejelentkezett összes felhasználót. A felhasználók ezután kiválaszthatnak egyet ezek közül a fiókok közül, és közvetlenül az üdvözlőképernyőre léphetnek anélkül, hogy újra be kellene írniuk a jelszót, mivel már hitelesítették a gép access.
A Nézetek mappában adjon hozzá egy új, "Welcome.xaml" nevű üres lapot. Adja hozzá a következő XAML-t a lap felhasználói felületének befejezéséhez. Ekkor megjelenik egy cím, a bejelentkezett felhasználónév és két gomb. Az egyik gomb visszakerül egy felhasználói listára (amelyet később fog létrehozni), a másik gomb pedig a felhasználó elfelejtését fogja kezelni.
<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>A Welcome.xaml.cs kód mögötti fájlban adjon hozzá egy új privát változót, amely a bejelentkezett fiókot fogja tárolni. Implementálnia kell egy metódust az
OnNavigateToesemény felülbírálásához, ez tárolja az üdvözlőlapra átadott fiókot. Önnek is implementálnia kell aClickeseményt a XAML-ben meghatározott két gombhoz. AWindowsHelloLogin.ModelsésWindowsHelloLogin.Utilsnévterekhez megfelelő 'using' utasításokat kell hozzáadnia.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."); } } }Lehet, hogy feltűnhetett Önnek egy kikommentelt sor a
Button_Forget_User_Clickeseménykezelőben. Eltávolítják a fiókot a helyi listáról, de jelenleg nincs mód a Windows Hello-ról való eltávolításra. Új módszert kell implementálnia a WindowsHelloHelper.cs, amely egy Windows Hello felhasználó eltávolítását fogja kezelni. Ez a módszer más Windows Hello API-kat használ a fiók megnyitásához és törléséhez. A valós világban, amikor töröl egy fiókot, a kiszolgálót vagy az adatbázist értesíteni kell, hogy a felhasználói adatbázis érvényes maradjon. Szüksége lesz egy, aWindowsHelloLogin.Modelsnévtérre hivatkozó utasításra.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); }Lépjen vissza Welcome.xaml.cs, és bontsa ki a RemoveWindowsHelloAccountAsync hívását kezdeményező sort.
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."); }A SignInWindowsHelloAsync metódusban (Login.xaml.cs), amikor a CreateWindowsHelloKeyAsync sikeresen létrejön, a rendszer az Üdvözlés oldalra kell, hogy navigáljon, és adja át a Fiókot.
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"; } }Hozza létre és futtassa az alkalmazást. Jelentkezzen be a "sampleUsername" névvel, és kattintson a Bejelentkezés gombra. Adja meg a PIN-kódot, és ha sikeres, az üdvözlőképernyőre kell navigálnia. Kattintson a Felhasználó elfelejtése elemre, majd figyelje a Visual Studio Output ablakát, hogy a felhasználó törölve lett-e. Figyelje meg, hogy a felhasználó törlésekor az üdvözlőoldalon marad. Létre kell hoznia egy felhasználói kijelölési lapot, amelyen az alkalmazás navigálhat.
A Nézetek mappában hozzon létre egy új üres lapot "UserSelection.xaml" néven, és adja hozzá a következő XAML-t a felhasználói felület meghatározásához. Ez a lap egy ListView-t tartalmaz, amely megjeleníti a helyi fiókok listájában szereplő összes felhasználót, és a
Buttonbejelentkezési lapra lépve lehetővé teszi a felhasználó számára egy másik fiók hozzáadását.<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>A UserSelection.xaml.cs implementálja azt a
Loadedmetódust, amely a Bejelentkezési lapra lép, ha nincsenek fiókok a helyi listában. Implementáljon egySelectionChangedeseményt aListViewszámára, és egyClickeseményt aButtonszámára.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)); } } }Az alkalmazásban van néhány hely, ahol a UserSelection oldalra szeretne navigálni. A MainPage.xaml.cs fájlban a Bejelentkezés lap helyett a UserSelection lapra kell navigálnia. Amíg a MainPage betöltési eseményében van, be kell töltenie a fióklistát, hogy a UserSelection oldal ellenőrizni tudja, hogy vannak-e fiókok. Ehhez módosítani kell a
Loadedmetódust aszinkron módon, és hozzá kell adni egy használati utasítást aWindowsHelloLogin.Utilsnévtérhez.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)); }Ezután az alkalmazásnak az üdvözlőlapon kell navigálnia a UserSelection lapra. Mindkét
Clickeseménynél vissza kell lépnie a UserSelection lapra.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)); }A Bejelentkezési lapon a UserSelection lapon a listából kiválasztott fiókba való bejelentkezéshez kód szükséges. Ebben az
OnNavigatedToeseményben tárolja a navigáció során átadott fiókot. Először adjon hozzá egy új privát változót, amely azonosítja, hogy a fiók meglévő fiók-e. AzOnNavigatedToeseményt ezután kezelje.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; } } } }A SignInWindowsHelloAsync metódust frissíteni kell a kiválasztott fiókba való bejelentkezéshez. A WindowsHelloHelper egy másik metódusra lesz szüksége a fiók Windows Hello való megnyitásához, mivel a fiókhoz már létrehozott egy fiókkulcsot. Implementálja az új módszert a WindowsHelloHelper.cs fájlban egy meglévő felhasználó bejelentkezéséhez a Windows Hello használatával. A kód minden részével kapcsolatos információkért olvassa el a kód megjegyzéseit.
/// <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; }Frissítse a SignInWindowsHelloAsync metódust Login.xaml.cs a meglévő fiók kezeléséhez. Ez az új metódust fogja használni a WindowsHelloHelper.cs. Ha sikeres, a fiók be lesz jelentkezve, és a felhasználó az üdvözlőoldalra navigál.
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"; } }Hozza létre és futtassa az alkalmazást. Jelentkezzen be a "sampleUsername" névvel. Írja be a PIN-kódot, és ha sikeres, a rendszer az üdvözlőoldalra navigál. Kattintson vissza a felhasználói listára. Most már látnia kell egy felhasználót a listában. Ha erre kattint, a WindowsHello lehetővé teszi a bejelentkezést anélkül, hogy újra be kellene írnia a jelszavakat stb.
3. gyakorlat: Új Windows Hello felhasználó regisztrálása
Ebben a gyakorlatban létrehoz egy új oldalt, amely lehetővé teszi egy új fiók létrehozását a Windows Hellóval. Ez a bejelentkezési oldal működéséhez hasonlóan működik. A Login lap egy olyan meglévő felhasználóhoz van implementálva, aki Windows Hello szeretne használni. A WindowsHelloRegister lapon Windows Hello új felhasználó regisztrációja jön létre.
A Nézetek mappában hozzon létre egy új üres lapot "WindowsHelloRegister.xaml" néven. Az XAML-ben adja hozzá az alábbiakat a felhasználói felület beállításához. Az oldal felülete hasonló a Bejelentkezési laphoz.
<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>A WindowsHelloRegister.xaml.cs kód mögötti fájlban implementáljon egy privát
Accountváltozót és egy eseménytClicka regisztrációs gombhoz. Ezzel hozzáad egy új helyi fiókot, és létrehoz egy Windows Hello kulcsot.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"; } } } }Erre a lapra kell navigálnia a bejelentkezési lapról, amikor a regisztrációra kattint.
private void RegisterButtonTextBlock_OnPointerPressed(object sender, PointerRoutedEventArgs e) { ErrorMessage.Text = ""; Frame.Navigate(typeof(WindowsHelloRegister)); }Hozza létre és futtassa az alkalmazást. Próbáljon meg új felhasználót regisztrálni. Ezután térjen vissza a felhasználói listához, és ellenőrizze, hogy kiválaszthatja-e a felhasználót, és bejelentkezhet-e.
Ebben a laborban elsajátította azokat az alapvető készségeket, amelyek szükségesek ahhoz, hogy az új Windows Hello API-val hitelesítse a meglévő felhasználókat, és új felhasználók számára hozzon létre fiókokat. Ezzel az új tudással megszüntetheti annak szükségességét, hogy a felhasználók megjegyezzenek az alkalmazáshoz tartozó jelszavakat, de továbbra is biztosak lehetnek abban, hogy az alkalmazások felhasználói hitelesítéssel védettek maradnak. A Windows Windows Hello új hitelesítési technológiájával támogatja a biometrikus bejelentkezési lehetőségeket.
Kapcsolódó témakörök
Windows developer