Anteckning
Åtkomst till den här sidan kräver auktorisering. Du kan prova att logga in eller ändra kataloger.
Åtkomst till den här sidan kräver auktorisering. Du kan prova att ändra kataloger.
              Gäller för:  arbetskraftsaktörer
 arbetskraftsaktörer  externa klienter (läs mer)
 externa klienter (läs mer)
Den här självstudien visar hur du skapar en WPF-skrivbordsapp (Windows Presentation Form) och förbereder den för autentisering med hjälp av administrationscentret för Microsoft Entra.
I den här handledningen kommer du att:
- Konfigurera en WPF-skrivbordsapp så att den använder appregistreringsinformation.
- Skapa en skrivbordsapp som loggar in en användare och hämtar en token åt användaren.
Förutsättningar
- Registrera en ny app i administrationscentret för Microsoft Entra, konfigurerad för konton i alla organisationskataloger och personliga Microsoft-konton. Mer information finns i Registrera ett program . Registrera följande värden från programöversiktssidan för senare användning: - App-ID (klient-ID)
- Katalog-ID (hyresgäst)
- Katalogdomännamn (klientorganisation) (till exempel contoso.onmicrosoft.com eller contoso.com).
 
- Lägg till följande omdirigerings-URI:er med hjälp av plattformskonfigurationen för mobil- och skrivbordsprogram . Mer information finns i Så här lägger du till en omdirigerings-URI i ditt program .
- 
              omdirigerings-URI: https://login.microsoftonline.com/common/oauth2/nativeclient
 
- 
              omdirigerings-URI: 
- Associera din app med ett användarflöde i administrationscentret för Microsoft Entra. Det här användarflödet kan användas i flera program. Mer information finns i Skapa användarflöden för självbetjäningsregistrering för appar i externa klienter och Lägg till ditt program i användarflödet.
- .NET 7.0 SDK eller senare.
- Även om vilken integrerad utvecklingsmiljö (IDE) som helst som stöder React-applikationer kan användas, använder den här handledningen Visual Studio Code.
Skapa ett WPF-skrivbordsprogram
- Öppna terminalen och gå till mappen där du vill att projektet ska finnas. 
- Initiera en WPF-skrivbordsapp och navigera till rotmappen. - dotnet new wpf --language "C#" --name sign-in-dotnet-wpf cd sign-in-dotnet-wpf
Installera paket
Installera konfigurationsleverantörer som hjälper programmet att läsa konfigurationsdata från nyckel/värde-par i programinställningsfilen. Dessa konfigurationsabstraktioner ger möjlighet att binda konfigurationsvärden till instanser av .NET-objekt.
dotnet add package Microsoft.Extensions.Configuration
dotnet add package Microsoft.Extensions.Configuration.Json
dotnet add package Microsoft.Extensions.Configuration.Binder
Installera Microsoft Authentication Library (MSAL) som innehåller alla viktiga komponenter som du behöver för att hämta en token. Du installerar också MSAL-koordinatorbiblioteket som hanterar interaktioner med autentiseringskoordinatorer för skrivbord.
dotnet add package Microsoft.Identity.Client
dotnet add package Microsoft.Identity.Client.Broker
Skapa appsettings.json fil och lägg till registreringskonfigurationer
- Skapa appsettings.json fil i appens rotmapp. 
- Lägg till appregistreringsinformation i appsettings.json-filen. - { "AzureAd": { "Authority": "https://<Enter_the_Tenant_Subdomain_Here>.ciamlogin.com/", "ClientId": "<Enter_the_Application_Id_Here>" } }- Ersätt Enter_the_Tenant_Subdomain_Heremed katalogens (klientorganisationens) underdomän.
- Ersätt Enter_the_Application_Id_Heremed program-ID:t (klient) för den app som du registrerade tidigare.
 
- Ersätt 
- När du har skapat appinställningsfilen skapar vi en annan fil med namnet AzureAdConfig.cs som hjälper dig att läsa konfigurationerna från appinställningsfilen. Skapa AzureAdConfig.cs-filen i appens rotmapp. 
- I filen AzureAdConfig.js definierar du getters och setters för - ClientIdegenskaperna och- Authority. Lägg till följande kod:- namespace sign_in_dotnet_wpf { public class AzureAdConfig { public string Authority { get; set; } public string ClientId { get; set; } } }
Använda anpassad URL-domän (valfritt)
Använd en anpassad domän för att helt märka autentiserings-URL:en. Från ett användarperspektiv finns användarna kvar på din domän under autentiseringsprocessen, i stället för att omdirigeras till ciamlogin.com domännamn.
Följ dessa steg för att använda en anpassad domän:
- Använd stegen i Aktivera anpassade URL-domäner för appar i externa klienter för att aktivera anpassad URL-domän för din externa klientorganisation. 
- Öppna appsettings.json fil: - Uppdatera värdet för Authorityegenskapen till https://Enter_the_Custom_Domain_Here/Enter_the_Tenant_ID_Here. ErsättEnter_the_Custom_Domain_Heremed din anpassade URL-domän ochEnter_the_Tenant_ID_Heremed ditt klient-ID. Om du inte har ditt klientorganisations-ID kan du lära dig hur du läser dina klientorganisationsuppgifter.
- Lägg till egenskapen knownAuthoritiesmed värdet [Enter_the_Custom_Domain_Here].
 
- Uppdatera värdet för 
När du har gjort ändringarna i din appsettings.json-fil , om din anpassade URL-domän är login.contoso.com och klientorganisations-ID:t är aaaabbbb-0000-cccc-1111-dddd222eeee, bör filen se ut ungefär så här:
{
    "AzureAd": {
        "Authority": "https://login.contoso.com/aaaabbbb-0000-cccc-1111-dddd2222eeee",
        "ClientId": "Enter_the_Application_Id_Here",
        "KnownAuthorities": ["login.contoso.com"]
    }
}
Ändra projektfilen
- Navigera till filen sign-in-dotnet-wpf.csproj i appens rotmapp. 
- I den här filen utför du följande två steg: - Ändra filen sign-in-dotnet-wpf.csproj för att instruera din app att kopiera appsettings.json-filen till utdatakatalogen när projektet kompileras. Lägg till följande kod i filen sign-in-dotnet-wpf.csproj :
- Ange målramverket till windows10.0.19041.0 för att underlätta läsning av cachelagrade tokens från tokencachen, vilket du ser i hjälpklassen för tokencache.
 - <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>
Skapa en token-cache-hjälpklass
Skapa en hjälparklass för tokencache som initierar ett token cache. Programmet försöker läsa token från cacheminnet innan det försöker hämta en ny token. Om token inte hittas i cacheminnet hämtar programmet en ny token. Vid utloggning rensas cacheminnet från alla konton och alla motsvarande åtkomsttoken.
- Skapa en TokenCacheHelper.cs fil i appens rotmapp. 
- Öppna filen TokenCacheHelper.cs . Lägg till paketen och namnrymderna i filen. I följande steg fyller du i den här filen med kodlogik genom att lägga till relevant logik i - TokenCacheHelperklassen.- using System.IO; using System.Security.Cryptography; using Microsoft.Identity.Client; namespace sign_in_dotnet_wpf { static class TokenCacheHelper{} }
- Lägg till konstruktor i klassen - TokenCacheHelpersom definierar cachefilens sökväg. För paketerade skrivbordsappar (MSIX-paket, även kallade desktop bridge) är körmappen skrivskyddad. I så fall måste vi använda- Windows.Storage.ApplicationData.Current.LocalCacheFolder.Path + "\msalcache.bin"som är en läs-/skrivmapp per app för paketerade appar.- 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(); } }
- Lägg till kod för att hantera tokencachens serialisering. Gränssnittet - ITokenCacheimplementerar offentlig åtkomst till cacheåtgärder.- ITokenCachegränssnittet innehåller metoderna för att prenumerera på cache-serialiseringshändelserna, medan gränssnittet- ITokenCacheSerializerexponerar de metoder som du behöver använda i cache-serialiseringshändelserna för att serialisera/deserialisera cachen.- TokenCacheNotificationArgsinnehåller parametrar som används av- Microsoft.Identity.Client(MSAL) anrop till cachen.- ITokenCacheSerializer-gränssnittet är tillgängligt i- TokenCacheNotificationArgscallback-funktionen.- Lägg till följande kod i - TokenCacheHelperklassen:- 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); }- BeforeAccessNotificationI metoden läser du cachen från filsystemet och om cacheminnet inte är tomt deserialiserar du det och läser in det. Metoden- AfterAccessNotificationanropas efter att- Microsoft.Identity.Client(MSAL) har fått tillgång till cacheminnet. Om cacheminnet har ändrats serialiserar du det och sparar ändringarna i cacheminnet.- Den - EnableSerializationinnehåller metoderna- ITokenCache.SetBeforeAccess()och- ITokenCache.SetAfterAccess().- 
              ITokenCache.SetBeforeAccess()anger att ett ombud ska meddelas innan någon biblioteksmetod kommer åt cachen. Detta ger ombudet möjlighet att deserialisera en cachepost för programmet och kontona som anges iTokenCacheNotificationArgs.
- 
              ITokenCache.SetAfterAccess()anger att ett ombud ska meddelas när någon biblioteksmetod har åtkomst till cacheminnet. Detta ger ombudet möjlighet att serialisera ett cacheinlägg för applikationen och kontona som anges iTokenCacheNotificationArgs.
 
- 
              
Skapa WPF-skrivbordsappens användargränssnitt
              Ändra filen MainWindow.xaml för att lägga till användargränssnittselementen för appen. 
              Öppna filen MainWindow.xaml i appens rotmapp och lägg till följande kod med kontrollavsnittet<Grid></Grid>.
    <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>
Den här koden lägger till viktiga gränssnittselement. De metoder och objekt som hanterar funktionerna i användargränssnittselementen definieras i den MainWindow.xaml.cs fil som vi skapar i nästa steg.
- En knapp som loggar in användaren. 
              SignInButton_Click-metoden anropas när användaren väljer den här knappen.
- En knapp som loggar ut användaren. 
              SignOutButton_Click-metoden anropas när användaren väljer den här knappen.
- En textruta som visar information om autentiseringsresultatet när användaren försöker logga in. Information som visas här returneras av ResultTextobjektet.
- En textruta som visar tokeninformationen när användaren har loggat in. Information som visas här returneras av TokenInfoTextobjektet.
Lägga till kod i MainWindow.xaml.cs-filen
Filen MainWindow.xaml.cs innehåller den kod som tillhandahåller körningslogiken för beteendet hos användargränssnittselementen i filen MainWindow.xaml.
- Öppna filen MainWindow.xaml.cs i appens rotmapp. 
- Lägg till följande kod i filen för att importera paketen och definiera platshållare för de metoder vi skapar. - 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){...} } }
- Lägg till följande kod i metoden - SignInButton_Click. Den här metoden anropas när användaren väljer knappen Logga in .- 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()returnerar alla tillgängliga konton i appens cacheminne för användartoken. Gränssnittet- IAccountrepresenterar information om ett enda konto.- För att hämta token försöker appen hämta token tyst med hjälp av - AcquireTokenSilentmetoden för att kontrollera om en acceptabel token finns i cacheminnet. Metoden- AcquireTokenSilentkan till exempel misslyckas eftersom användaren loggade ut. När MSAL upptäcker att problemet kan lösas genom att kräva en interaktiv åtgärd utlöser det ett- MsalUiRequiredExceptionundantag. Det här undantaget gör att appen hämtar en token interaktivt.- AcquireTokenInteractiveAtt anropa metoden resulterar i ett fönster som uppmanar användarna att logga in. Appar kräver vanligtvis att användarna loggar in interaktivt första gången de behöver autentisera. De kan också behöva logga in vid en tyst operation för att hämta en token. När- AcquireTokenInteractivehar körts för första gången- AcquireTokenSilentblir den vanliga metoden att använda för att hämta token
- Lägg till följande kod i metoden - SignOutButton_Click. Den här metoden anropas när användaren väljer knappen Logga ut .- 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}"; } } }- Metoden - SignOutButton_Clickrensar cachen för alla konton och alla motsvarande åtkomsttoken. Nästa gång användaren försöker logga in måste de göra det interaktivt.
- Lägg till följande kod i metoden - DisplayBasicTokenInfo. Den här metoden visar grundläggande information om token.- 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; } }
Lägga till kod i App.xaml.cs-filen
App.xaml är där du deklarerar resurser som används i hela appen. Det är startpunkten för din app. App.xaml.cs är koden bakom filen för App.xaml. App.xaml.cs definierar även startfönstret för ditt program.
Öppna filen App.xaml.cs i appens rotmapp och lägg sedan till följande kod i den.
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; } }
    }
}
I det här steget läser du in filen appsettings.json . Konfigurationsverktyget hjälper dig att läsa appkonfigurationerna som definierats i filen appsettings.json . Du definierar även WPF-appen som en offentlig klientapp eftersom det är en skrivbordsapp. Metoden TokenCacheHelper.EnableSerialization aktiverar tokencachens serialisering.
Kör appen
Kör appen och logga in för att testa programmet
- I terminalen går du till rotmappen för WPF-appen och kör appen genom att köra kommandot - dotnet runi terminalen.
- När du har lanserat exemplet bör du se ett fönster med en inloggningsknapp . Välj knappen Logga in.   
- På inloggningssidan anger du ditt kontos e-postadress. Om du inte har något konto väljer du Inget konto? Skapa en, som startar registreringsflödet. Följ det här flödet för att skapa ett nytt konto och logga in. 
- När du har loggat in visas en skärm som visar lyckad inloggning och grundläggande information om ditt användarkonto som lagras i den hämtade token. Grundläggande information visas i avsnittet Tokeninformation på inloggningsskärmen