Sdílet prostřednictvím


Kurz: Ověřování uživatelů v desktopové aplikaci WPF

Platí pro: Zelený kruh se symbolem bílé značky zaškrtnutí, který označuje následující obsah platí pro externí tenanty. Externí tenanti (další informace)

Tento kurz ukazuje, jak vytvořit desktopovou aplikaci WPF (Windows Presentation Form) a připravit ji na ověřování pomocí Centra pro správu Microsoft Entra.

V tomto kurzu se naučíte:

  • Nakonfigurujte desktopovou aplikaci WPF tak, aby používala podrobnosti o registraci aplikace.
  • Vytvořte desktopovou aplikaci, která přihlásí uživatele a získá token jménem uživatele.

Požadavky

Vytvoření desktopové aplikace WPF

  1. Otevřete terminál a přejděte do složky, ve které má projekt žít.

  2. Inicializuje desktopovou aplikaci WPF a přejde do její kořenové složky.

    dotnet new wpf --language "C#" --name sign-in-dotnet-wpf
    cd sign-in-dotnet-wpf
    

Instalace balíčků

Nainstalujte zprostředkovatele konfigurace, kteří aplikaci pomáhají číst konfigurační data z párů klíč-hodnota v souboru nastavení aplikace. Tyto abstrakce konfigurace poskytují možnost svázat konfigurační hodnoty s instancemi objektů .NET.

dotnet add package Microsoft.Extensions.Configuration
dotnet add package Microsoft.Extensions.Configuration.Json
dotnet add package Microsoft.Extensions.Configuration.Binder

Nainstalujte knihovnu MSAL (Microsoft Authentication Library), která obsahuje všechny klíčové komponenty, které potřebujete k získání tokenu. Také nainstalujete knihovnu zprostředkovatele MSAL, která zpracovává interakce se zprostředkovateli ověřování na ploše.

dotnet add package Microsoft.Identity.Client
dotnet add package Microsoft.Identity.Client.Broker

Vytvoření souboru appsettings.json a přidání konfigurací registrace

  1. Vytvořte soubor appsettings.json v kořenové složce aplikace.

  2. Do souboru appsettings.json přidejte podrobnosti o registraci aplikace.

    {
        "AzureAd": {
            "Authority": "https://<Enter_the_Tenant_Subdomain_Here>.ciamlogin.com/",
            "ClientId": "<Enter_the_Application_Id_Here>"
        }
    }
    
    • Nahraďte Enter_the_Tenant_Subdomain_Here subdoménou adresáře (tenanta).
    • Nahraďte Enter_the_Application_Id_Here IDem aplikace (klienta), kterou jste zaregistrovali dříve.
  3. Po vytvoření souboru nastavení aplikace vytvoříme další soubor s názvem AzureAdConfig.cs , který vám pomůže číst konfigurace ze souboru nastavení aplikace. Vytvořte soubor AzureAdConfig.cs v kořenové složce aplikace.

  4. V souboru AzureAdConfig.js definujte gettery a settery pro ClientId a Authority. Přidejte následující kód:

    namespace sign_in_dotnet_wpf
    {
        public class AzureAdConfig
        {
            public string Authority { get; set; }
            public string ClientId { get; set; }
        }
    }
    

Použití vlastní domény URL (volitelné)

Použijte vlastní doménu pro zajištění plného brandingu URL ověřování. Z uživatelského pohledu zůstanou uživatelé ve vaší doméně během procesu ověřování, a nejsou přesměrováni na doménu ciamlogin.com.

Pokud chcete použít vlastní doménu, postupujte takto:

  1. Pomocí kroků v Povolení vlastních domén URL pro aplikace v externích tenantech povolte pro externího tenanta vlastní doménu URL.

  2. Otevřete soubor appsettings.json:

    1. Aktualizujte hodnotu vlastnosti Authority na https://Enter_the_Custom_Domain_Here/Enter_the_Tenant_ID_Here. Nahraďte Enter_the_Custom_Domain_Here vlastní doménou URL a Enter_the_Tenant_ID_Here ID tenanta. Pokud nemáte ID tenanta, zjistěte, jak získat podrobnosti o tenantovi.
    2. Přidejte vlastnost knownAuthorities s hodnotou [Enter_the_Custom_Domain_Here].

Po provedení změn souboru appsettings.json , pokud je vaše vlastní doména URL login.contoso.com a ID vašeho tenanta je aaaabbbb-0000-cccc-1111-dddd2222eeeee, měl by váš soubor vypadat podobně jako následující fragment kódu:

{
    "AzureAd": {
        "Authority": "https://login.contoso.com/aaaabbbb-0000-cccc-1111-dddd2222eeee",
        "ClientId": "Enter_the_Application_Id_Here",
        "KnownAuthorities": ["login.contoso.com"]
    }
}

Úprava souboru projektu

  1. Přejděte do souboru sign-in-dotnet-wpf.csproj v kořenové složce aplikace.

  2. V tomto souboru proveďte následující dva kroky:

    1. Upravte soubor sign-in-dotnet-wpf.csproj, aby aplikace při kompilaci projektu zkopírovala soubor appsettings.json do výstupního adresáře. Do souboru sign-in-dotnet-wpf.csproj přidejte následující kód:
    2. Nastavte cílový framework na verzi build windows10.0.19041.0, která vám pomůže při čtení tokenu z mezipaměti tokenů, jak můžete vidět v pomocné třídě pro mezipaměť tokenů.
    <Project Sdk="Microsoft.NET.Sdk">
    
        ...
    
        <!-- Set target framework to target windows10.0.19041.0 build -->
        <PropertyGroup>
            <OutputType>WinExe</OutputType>
            <TargetFramework>net7.0-windows10.0.19041.0</TargetFramework> <!-- target framework -->
            <RootNamespace>sign_in_dotnet_wpf</RootNamespace>
            <Nullable>enable</Nullable>
            <UseWPF>true</UseWPF>
        </PropertyGroup>
    
        <!-- Copy appsettings.json file to output folder. -->
        <ItemGroup>
            <None Remove="appsettings.json" />
        </ItemGroup>
    
        <ItemGroup>
            <EmbeddedResource Include="appsettings.json">
                <CopyToOutputDirectory>Always</CopyToOutputDirectory>
            </EmbeddedResource>
        </ItemGroup>
    </Project>
    

Vytvoření pomocné třídy mezipaměti tokenů

Vytvořte pomocnou třídu mezipaměti tokenů, která inicializuje mezipaměť tokenů. Aplikace se pokusí načíst token z mezipaměti předtím, než se pokusí získat nový token. Pokud se token v mezipaměti nenajde, aplikace získá nový token. Po odhlášení se mezipaměť vymaže ze všech účtů a všech odpovídajících přístupových tokenů.

  1. Vytvořte soubor TokenCacheHelper.cs v kořenové složce aplikace.

  2. Otevřete soubor TokenCacheHelper.cs. Přidejte do souboru balíčky a obory názvů. V následujících krocích naplníte tento soubor logikou kódu přidáním příslušné logiky do TokenCacheHelper třídy.

    using System.IO;
    using System.Security.Cryptography;
    using Microsoft.Identity.Client;
    
    namespace sign_in_dotnet_wpf
    {
        static class TokenCacheHelper{}
    }
    
  3. Přidejte konstruktor do TokenCacheHelper třídy, která definuje cestu k souboru mezipaměti. Pro zabalené desktopové aplikace (balíčky MSIX, označované také jako desktopová propojení) je složka prováděcího sestavení určená pouze pro čtení. V takovém případě musíme použít Windows.Storage.ApplicationData.Current.LocalCacheFolder.Path + "\msalcache.bin", což je složka pro čtení a zápis pro každou aplikaci určená pro balíčkované aplikace.

    namespace sign_in_dotnet_wpf
    {
        static class TokenCacheHelper
        {
            static TokenCacheHelper()
            {
                try
                {
                    CacheFilePath = Path.Combine(Windows.Storage.ApplicationData.Current.LocalCacheFolder.Path, ".msalcache.bin3");
                }
                catch (System.InvalidOperationException)
                {
                    CacheFilePath = System.Reflection.Assembly.GetExecutingAssembly().Location + ".msalcache.bin3";
                }
            }
            public static string CacheFilePath { get; private set; }
            private static readonly object FileLock = new object();
        }
    }
    
    
  4. Přidejte kód pro zpracování serializace mezipaměti tokenů. Rozhraní ITokenCache implementuje veřejný přístup k operacím mezipaměti. ITokenCache rozhraní obsahuje metody pro přihlášení k odběru událostí serializace mezipaměti, zatímco rozhraní ITokenCacheSerializer poskytuje metody, které potřebujete použít v událostech serializace mezipaměti, abyste mohli provádět serializaci/deserializaci mezipaměti. TokenCacheNotificationArgs obsahuje parametry používané volánímMicrosoft.Identity.Client MSAL, které přistupuje k mezipaměti. ITokenCacheSerializer rozhraní je dostupné v TokenCacheNotificationArgs callbacku.

    Do třídy TokenCacheHelper přidejte následující kód:

        static class TokenCacheHelper
        {
            static TokenCacheHelper()
            {...}
            public static string CacheFilePath { get; private set; }
            private static readonly object FileLock = new object();
    
            public static void BeforeAccessNotification(TokenCacheNotificationArgs args)
            {
                lock (FileLock)
                {
                    args.TokenCache.DeserializeMsalV3(File.Exists(CacheFilePath)
                            ? ProtectedData.Unprotect(File.ReadAllBytes(CacheFilePath),
                                                     null,
                                                     DataProtectionScope.CurrentUser)
                            : null);
                }
            }
    
            public static void AfterAccessNotification(TokenCacheNotificationArgs args)
            {
                if (args.HasStateChanged)
                {
                    lock (FileLock)
                    {
                        File.WriteAllBytes(CacheFilePath,
                                           ProtectedData.Protect(args.TokenCache.SerializeMsalV3(),
                                                                 null,
                                                                 DataProtectionScope.CurrentUser)
                                          );
                    }
                }
            }
        }
    
        internal static void EnableSerialization(ITokenCache tokenCache)
        {
            tokenCache.SetBeforeAccess(BeforeAccessNotification);
            tokenCache.SetAfterAccess(AfterAccessNotification);
        }
    

    BeforeAccessNotification V metodě načtete mezipaměť ze systému souborů a pokud mezipaměť není prázdná, deserializujete ji a načtete ji. Metoda AfterAccessNotification se volá poté, co Microsoft.Identity.Client (MSAL) přistupuje k mezipaměti. Pokud se mezipaměť změnila, serializujete ji a zachovají se změny v mezipaměti.

    Systém EnableSerialization obsahuje metody ITokenCache.SetBeforeAccess() a ITokenCache.SetAfterAccess().

    • ITokenCache.SetBeforeAccess() nastaví delegáta, který má být upozorněn před přístupem jakékoli metody knihovny k mezipaměti. To dává delegátu možnost deserializovat položku mezipaměti pro aplikaci a účty zadané v souboru TokenCacheNotificationArgs.
    • ITokenCache.SetAfterAccess() nastaví delegáta, který bude upozorněn po každém přístupu metody knihovny k mezipaměti. To dává delegátu možnost serializovat položku mezipaměti pro aplikaci a účty zadané v souboru TokenCacheNotificationArgs.

Vytvoření uživatelského rozhraní desktopové aplikace WPF

Upravte soubor MainWindow.xaml a přidejte prvky uživatelského rozhraní pro aplikaci. Otevřete soubor MainWindow.xaml v kořenové složce aplikace a přidejte následující část kódu s <Grid></Grid> částí ovládacího prvku.

    <StackPanel Background="Azure">
        <StackPanel Orientation="Horizontal" HorizontalAlignment="Right">
            <Button x:Name="SignInButton" Content="Sign-In" HorizontalAlignment="Right" Padding="5" Click="SignInButton_Click" Margin="5" FontFamily="Segoe Ui"/>
            <Button x:Name="SignOutButton" Content="Sign-Out" HorizontalAlignment="Right" Padding="5" Click="SignOutButton_Click" Margin="5" Visibility="Collapsed" FontFamily="Segoe Ui"/>
        </StackPanel>
        <Label Content="Authentication Result" Margin="0,0,0,-5" FontFamily="Segoe Ui" />
        <TextBox x:Name="ResultText" TextWrapping="Wrap" MinHeight="120" Margin="5" FontFamily="Segoe Ui"/>
        <Label Content="Token Info" Margin="0,0,0,-5" FontFamily="Segoe Ui" />
        <TextBox x:Name="TokenInfoText" TextWrapping="Wrap" MinHeight="70" Margin="5" FontFamily="Segoe Ui"/>
    </StackPanel>

Tento kód přidá klíčové prvky uživatelského rozhraní. Metody a objekty, které zpracovávají funkčnost prvků uživatelského rozhraní, jsou definovány v MainWindow.xaml.cs souboru, který vytvoříme v dalším kroku.

  • Tlačítko, které uživatele přihlásí. SignInButton_Click metoda je volána, když uživatel vybere toto tlačítko.
  • Tlačítko, které uživatele odhlásí. SignOutButton_Click metoda je volána, když uživatel vybere toto tlačítko.
  • Textové pole, které zobrazuje podrobnosti výsledku ověření po pokusu uživatele o přihlášení. Informace zobrazené zde vrácené objektem ResultText .
  • Textové pole, které zobrazí podrobnosti tokenu po úspěšném přihlášení uživatele. Informace zobrazené zde vrácené objektem TokenInfoText .

Přidání kódu do souboru MainWindow.xaml.cs

Soubor MainWindow.xaml.cs obsahuje kód, který poskytuje logiku modulu runtime pro chování prvků uživatelského rozhraní v souboru MainWindow.xaml .

  1. Otevřete soubor MainWindow.xaml.cs v kořenové složce aplikace.

  2. Do souboru přidejte následující kód pro import balíčků a definujte zástupné symboly pro metody, které vytvoříme.

    using Microsoft.Identity.Client;
    using System;
    using System.Linq;
    using System.Windows;
    using System.Windows.Interop;
    
    namespace sign_in_dotnet_wpf
    {
        public partial class MainWindow : Window
        {
            string[] scopes = new string[] { };
    
            public MainWindow()
            {
                InitializeComponent();
            }
    
            private async void SignInButton_Click(object sender, RoutedEventArgs e){...}
    
            private async void SignOutButton_Click(object sender, RoutedEventArgs e){...}
    
            private void DisplayBasicTokenInfo(AuthenticationResult authResult){...}
        }
    }
    
  3. Do metody SignInButton_Click přidejte následující kód. Tato metoda se volá, když uživatel vybere tlačítko Přihlásit se.

    private async void SignInButton_Click(object sender, RoutedEventArgs e)
    {
        AuthenticationResult authResult = null;
        var app = App.PublicClientApp;
    
        ResultText.Text = string.Empty;
        TokenInfoText.Text = string.Empty;
    
        IAccount firstAccount;
    
        var accounts = await app.GetAccountsAsync();
        firstAccount = accounts.FirstOrDefault();
    
        try
        {
            authResult = await app.AcquireTokenSilent(scopes, firstAccount)
                    .ExecuteAsync();
        }
        catch (MsalUiRequiredException ex)
        {
            try
            {
                authResult = await app.AcquireTokenInteractive(scopes)
                    .WithAccount(firstAccount)
                    .WithParentActivityOrWindow(new WindowInteropHelper(this).Handle) 
                    .WithPrompt(Prompt.SelectAccount)
                    .ExecuteAsync();
            }
            catch (MsalException msalex)
            {
                ResultText.Text = $"Error Acquiring Token:{System.Environment.NewLine}{msalex}";
            }
            catch (Exception ex)
            {
                ResultText.Text = $"Error Acquiring Token Silently:{System.Environment.NewLine}{ex}";
                return;
            }
    
            if (authResult != null)
            {
                ResultText.Text = "Sign in was successful.";
                DisplayBasicTokenInfo(authResult);
                this.SignInButton.Visibility = Visibility.Collapsed;
                this.SignOutButton.Visibility = Visibility.Visible;
            }
        }
    }
    

    GetAccountsAsync() vrátí všechny dostupné účty v mezipaměti tokenů uživatele pro aplikaci. Rozhraní IAccount představuje informace o jednom účtu.

    K získání tokenů se aplikace pokusí token získat bezobslužně pomocí AcquireTokenSilent metody, aby ověřila, jestli je v mezipaměti přijatelný token. Metoda AcquireTokenSilent může například selhat, protože se uživatel odhlásil. Když služba MSAL zjistí, že problém lze vyřešit vyžadováním interaktivní akce, vyvolá MsalUiRequiredException výjimku. Tato výjimka způsobí, že aplikace interaktivně získá token.

    AcquireTokenInteractive Volání metody způsobí, že se zobrazí okno s výzvou, aby se uživatelé přihlásili. Aplikace obvykle vyžadují, aby se uživatelé přihlašovali interaktivně při prvním ověření. Také se mohou potřebovat přihlásit, pokud se použije bezobslužná operace pro získání tokenu. Po prvním spuštění AcquireTokenInteractive se AcquireTokenSilent stane obvyklou metodou pro získání tokenů.

  4. Do metody SignOutButton_Click přidejte následující kód. Tato metoda se volá, když uživatel vybere tlačítko Odhlásit se .

    private async void SignOutButton_Click(object sender, RoutedEventArgs e)
    {
        var accounts = await App.PublicClientApp.GetAccountsAsync();
        if (accounts.Any())
        {
            try
            {
                await App.PublicClientApp.RemoveAsync(accounts.FirstOrDefault());
                this.ResultText.Text = "User has signed-out";
                this.TokenInfoText.Text = string.Empty;
                this.SignInButton.Visibility = Visibility.Visible;
                this.SignOutButton.Visibility = Visibility.Collapsed;
            }
            catch (MsalException ex)
            {
                ResultText.Text = $"Error signing-out user: {ex.Message}";
            }
        }
    }
    

    Metoda SignOutButton_Click vymaže mezipaměť všech účtů a všech odpovídajících přístupových tokenů. Až se uživatel příště pokusí přihlásit, bude to muset udělat interaktivně.

  5. Do metody DisplayBasicTokenInfo přidejte následující kód. Tato metoda zobrazí základní informace o tokenu.

    private void DisplayBasicTokenInfo(AuthenticationResult authResult)
    {
        TokenInfoText.Text = "";
        if (authResult != null)
        {
            TokenInfoText.Text += $"Username: {authResult.Account.Username}" + Environment.NewLine;
            TokenInfoText.Text += $"{authResult.Account.HomeAccountId}" + Environment.NewLine;
        }
    }
    

Přidání kódu do souboru App.xaml.cs

App.xaml je místo, kde deklarujete prostředky, které se používají v celé aplikaci. Je to vstupní bod pro vaši aplikaci. App.xaml.cs je kód za souborem app.xaml. App.xaml.cs také definuje úvodní okno pro vaši aplikaci.

Otevřete soubor App.xaml.cs v kořenové složce aplikace a přidejte do něj následující kód.

using System.Windows;
using System.Reflection;
using Microsoft.Identity.Client;
using Microsoft.Identity.Client.Broker;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.Configuration.Json;

namespace sign_in_dotnet_wpf
{
    public partial class App : Application
    {
        static App()
        {
            CreateApplication();
        }

        public static void CreateApplication()
        {
            var assembly = Assembly.GetExecutingAssembly();
            using var stream = assembly.GetManifestResourceStream("sign_in_dotnet_wpf.appsettings.json");
            AppConfiguration = new ConfigurationBuilder()
                .AddJsonStream(stream)
                .Build();

            AzureAdConfig azureADConfig = AppConfiguration.GetSection("AzureAd").Get<AzureAdConfig>();

            var builder = PublicClientApplicationBuilder.Create(azureADConfig.ClientId)
                .WithAuthority(azureADConfig.Authority)
                .WithDefaultRedirectUri();

            _clientApp = builder.Build();
            TokenCacheHelper.EnableSerialization(_clientApp.UserTokenCache);
        }

        private static IPublicClientApplication _clientApp;
        private static IConfiguration AppConfiguration;
        public static IPublicClientApplication PublicClientApp { get { return _clientApp; } }
    }
}

V tomto kroku načtete appsettings.json soubor. Tvůrce konfigurace vám pomůže číst konfigurace aplikací definované v souboru appsettings.json . Aplikaci WPF také definujete jako veřejnou klientskou aplikaci, protože se jedná o desktopovou aplikaci. Metoda TokenCacheHelper.EnableSerialization umožňuje serializaci mezipaměti tokenů.

Spuštění aplikace

Spuštění aplikace a přihlášení k otestování aplikace

  1. V terminálu přejděte do kořenové složky aplikace WPF a spusťte aplikaci spuštěním příkazu dotnet run v terminálu.

  2. Po spuštění ukázky by se mělo zobrazit okno s tlačítkem Přihlášení. Vyberte tlačítko Pro přihlášení.

    snímek obrazovky s přihlašovací obrazovkou pro desktopovou aplikaci WPF

  3. Na přihlašovací stránce zadejte e-mailovou adresu svého účtu. Pokud účet nemáte, vyberte Žádný účet? Vytvořte jeden, který spustí tok registrace. Projděte si tento tok a vytvořte nový účet a přihlaste se.

  4. Po přihlášení se zobrazí obrazovka s úspěšným přihlášením a základními informacemi o vašem uživatelském účtu uloženém v načteného tokenu. Základní informace se zobrazí v části Informace o tokenu na přihlašovací obrazovce.

Viz také