Uwaga
Dostęp do tej strony wymaga autoryzacji. Może spróbować zalogować się lub zmienić katalogi.
Dostęp do tej strony wymaga autoryzacji. Możesz spróbować zmienić katalogi.
Dotyczy: Najemcy pracowniczy
Najemcy zewnętrzni (dowiedz się więcej)
W tym samouczku pokazano, jak utworzyć aplikację klasyczną Windows Presentation Form (WPF) i przygotować ją do uwierzytelniania przy użyciu centrum administracyjnego firmy Microsoft Entra.
W tym samouczku nauczysz się następujących rzeczy:
- Skonfiguruj aplikację klasyczną WPF, aby korzystała ze szczegółów rejestracji aplikacji.
- Utwórz aplikację desktopową, która loguje użytkownika i uzyskuje token w jego imieniu.
Wymagania wstępne
- Zarejestruj nową aplikację w centrum administracyjnym firmy Microsoft Entra, skonfigurowaną dla kont w dowolnym katalogu organizacyjnym i osobistych kontach Microsoft. Aby uzyskać więcej informacji, zobacz Rejestrowanie aplikacji . Zapisz następujące wartości na stronie Przegląd aplikacji do późniejszego użycia:
- Identyfikator aplikacji (klienta)
- Identyfikator katalogu (klienta)
- Nazwa domeny katalogu (dzierżawy) (na przykład contoso.onmicrosoft.com lub contoso.com).
- Dodaj następujące identyfikatory URI przekierowania przy użyciu konfiguracji platformy aplikacje mobilne i desktopowe. Więcej informacji znajdziesz w Jak dodać adres URI przekierowania w aplikacji.
-
URI przekierowania:
https://login.microsoftonline.com/common/oauth2/nativeclient
-
URI przekierowania:
- Skojarz aplikację z przepływem użytkownika w centrum administracyjnym firmy Microsoft Entra. Ten przepływ użytkownika może być używany w wielu aplikacjach. Aby uzyskać więcej informacji, zobacz Tworzenie przepływów użytkowników rejestracji samoobsługowej dla aplikacji w dzierżawach zewnętrznych i Dodawanie aplikacji do przepływów użytkowników.
- Zestaw .NET 7.0 SDK lub nowszy.
- Mimo że można używać dowolnego zintegrowanego środowiska projektowego (IDE), które obsługuje aplikacje React, w tym samouczku jest używany program Visual Studio Code.
Stwórz aplikację WPF na komputer stacjonarny
Otwórz terminal i przejdź do folderu, w którym ma działać projekt.
Zainicjuj aplikację klasyczną WPF i przejdź do folderu głównego.
dotnet new wpf --language "C#" --name sign-in-dotnet-wpf cd sign-in-dotnet-wpf
Instalowanie pakietów
Zainstaluj dostawców konfiguracji, którzy pomagają naszej aplikacji odczytywać dane konfiguracji z par klucz-wartość w pliku ustawień aplikacji. Te abstrakcje konfiguracji umożliwiają powiązanie wartości konfiguracji z wystąpieniami obiektów platformy .NET.
dotnet add package Microsoft.Extensions.Configuration
dotnet add package Microsoft.Extensions.Configuration.Json
dotnet add package Microsoft.Extensions.Configuration.Binder
Zainstaluj bibliotekę Microsoft Authentication Library (MSAL), która zawiera wszystkie kluczowe składniki potrzebne do uzyskania tokenu. Należy również zainstalować bibliotekę brokera MSAL, która obsługuje interakcje z brokerami uwierzytelniania pulpitu.
dotnet add package Microsoft.Identity.Client
dotnet add package Microsoft.Identity.Client.Broker
Tworzenie pliku appsettings.json i dodawanie konfiguracji rejestracji
Utwórz plik appsettings.json w folderze głównym aplikacji.
Dodaj szczegóły rejestracji aplikacji do pliku appsettings.json .
{ "AzureAd": { "Authority": "https://<Enter_the_Tenant_Subdomain_Here>.ciamlogin.com/", "ClientId": "<Enter_the_Application_Id_Here>" } }
- Zastąp
Enter_the_Tenant_Subdomain_Here
poddomeną katalogu dla dzierżawcy. - Zastąp
Enter_the_Application_Id_Here
identyfikatorem aplikacji (klienta), którą zarejestrowałeś wcześniej.
- Zastąp
Po utworzeniu pliku ustawień aplikacji utworzymy inny plik o nazwie AzureAdConfig.cs , który pomoże Ci odczytać konfiguracje z pliku ustawień aplikacji. Utwórz plik AzureAdConfig.cs w folderze głównym aplikacji.
W pliku AzureAdConfig.js zdefiniuj metody getters i setters dla właściwości
ClientId
iAuthority
. Dodaj następujący kod:namespace sign_in_dotnet_wpf { public class AzureAdConfig { public string Authority { get; set; } public string ClientId { get; set; } } }
Użyj niestandardowej domeny adresu URL (opcjonalnie)
Użyj domeny niestandardowej, aby w pełni oznaczyć adres URL uwierzytelniania. Z perspektywy użytkownika użytkownicy pozostają na twojej domenie podczas procesu uwierzytelniania, a nie są przekierowywani na domenę ciamlogin.com.
Wykonaj następujące kroki, aby użyć domeny niestandardowej:
Aby włączyć niestandardową domenę URL dla twojej dzierżawy zewnętrznej, wykonaj kroki opisane w temacie Włączanie niestandardowych domen URL dla aplikacji w dzierżawach zewnętrznych.
Otwórz plik appsettings.json:
- Zaktualizuj wartość
Authority
właściwości na https://Enter_the_Custom_Domain_Here/Enter_the_Tenant_ID_Here. ZastąpEnter_the_Custom_Domain_Here
swoją własną domeną URL iEnter_the_Tenant_ID_Here
swoim identyfikatorem najemcy. Jeśli nie masz identyfikatora dzierżawy, dowiedz się, jak odczytywać szczegóły dzierżawy. - Dodaj
knownAuthorities
właściwość o wartości [Enter_the_Custom_Domain_Here].
- Zaktualizuj wartość
Po wprowadzeniu zmian w pliku appsettings.json, jeśli Twoja niestandardowa domena URL to login.contoso.com, a identyfikator dzierżawy to aaaabbbb-0000-cccc-1111-dddd2222eeee, plik powinien wyglądać podobnie do następującego fragmentu kodu:
{
"AzureAd": {
"Authority": "https://login.contoso.com/aaaabbbb-0000-cccc-1111-dddd2222eeee",
"ClientId": "Enter_the_Application_Id_Here",
"KnownAuthorities": ["login.contoso.com"]
}
}
Modyfikowanie pliku projektu
Przejdź do pliku sign-in-dotnet-wpf.csproj w folderze głównym aplikacji.
W tym pliku wykonaj następujące dwa kroki:
- Zmodyfikuj plik sign-in-dotnet-wpf.csproj , aby polecił aplikacji skopiowanie pliku appsettings.json do katalogu wyjściowego podczas kompilowania projektu. Dodaj następujący fragment kodu do pliku sign-in-dotnet-wpf.csproj :
- Ustaw platformę docelową na kompilację systemu Windows10.0.19041.0, aby ułatwić odczytywanie buforowanego tokenu z pamięci podręcznej tokenu, jak widać w klasie pomocniczej pamięci podręcznej tokenów.
<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>
Utwórz klasę pomocniczą pamięci podręcznej tokenu
Utwórz pomocniczą klasę pamięci podręcznej tokenów, która inicjuje pamięć podręczną tokenów. Aplikacja próbuje odczytać token z pamięci podręcznej, zanim podejmie próbę uzyskania nowego tokenu. Jeśli token nie zostanie znaleziony w pamięci podręcznej, aplikacja uzyska nowy token. Po wylogowaniu pamięć podręczna jest usuwana ze wszystkich kont i odpowiednich tokenów dostępu.
Utwórz plik TokenCacheHelper.cs w folderze głównym aplikacji.
Otwórz plik TokenCacheHelper.cs. Dodaj pakiety i przestrzenie nazw do pliku. W poniższych krokach należy wypełnić ten plik logiką kodu, dodając odpowiednią logikę
TokenCacheHelper
do klasy.using System.IO; using System.Security.Cryptography; using Microsoft.Identity.Client; namespace sign_in_dotnet_wpf { static class TokenCacheHelper{} }
Dodaj konstruktora do
TokenCacheHelper
klasy, która definiuje ścieżkę pliku pamięci podręcznej. W przypadku spakowanych aplikacji klasycznych (pakietów MSIX, nazywanych również Desktop Bridge) folder wykonywanej biblioteki jest tylko do odczytu. W takim przypadku musimy użyćWindows.Storage.ApplicationData.Current.LocalCacheFolder.Path + "\msalcache.bin"
, który jest folderem do odczytu/zapisu dla aplikacji spakowanych.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(); } }
Dodaj kod do obsługi serializacji pamięci podręcznej tokenu. Interfejs
ITokenCache
implementuje publiczny dostęp do operacji pamięci podręcznej.ITokenCache
interfejs zawiera metody subskrybowania zdarzeń serializacji pamięci podręcznej, podczas gdy interfejsITokenCacheSerializer
uwidacznia metody, których należy użyć w zdarzeniach serializacji pamięci podręcznej, w celu serializacji/deserializacji pamięci podręcznej.TokenCacheNotificationArgs
zawiera parametry używane przezMicrosoft.Identity.Client
wywołanie MSAL , które uzyskuje dostęp do pamięci podręcznej.ITokenCacheSerializer
interfejs jest dostępny wTokenCacheNotificationArgs
wywołaniu zwrotnym.Dodaj następujący kod do
TokenCacheHelper
klasy: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); }
W metodzie
BeforeAccessNotification
odczytasz pamięć podręczną z systemu plików, a jeśli pamięć podręczna nie jest pusta, zdeserializujesz ją i załadujesz. MetodaAfterAccessNotification
jest wywoływana po uzyskaniu dostępu do cache przez bibliotekę MSALMicrosoft.Identity.Client
. Jeśli pamięć podręczna uległa zmianie, należy ją serializować i utrwalać zmiany w pamięci podręcznej.Element
EnableSerialization
zawiera metodyITokenCache.SetBeforeAccess()
orazITokenCache.SetAfterAccess()
:-
ITokenCache.SetBeforeAccess()
Ustawia pełnomocnika, który ma być powiadamiany, zanim jakakolwiek metoda biblioteki uzyska dostęp do pamięci podręcznej. To daje opcję dla delegata do deserializacji wpisu pamięci podręcznej dla aplikacji i kont wskazanych w plikuTokenCacheNotificationArgs
. -
ITokenCache.SetAfterAccess()
Ustawia delegata, który ma być powiadamiany po uzyskaniu dostępu do pamięci podręcznej przez dowolną metodę biblioteki. To przekazuje delegatowi możliwość zserializowania wpisu pamięci podręcznej dla aplikacji i kont określonych wTokenCacheNotificationArgs
.
-
Tworzenie interfejsu użytkownika aplikacji desktopowej WPF
Zmodyfikuj plik MainWindow.xaml , aby dodać elementy interfejsu użytkownika dla aplikacji.
Otwórz plik MainWindow.xaml w folderze głównym aplikacji i dodaj następujący fragment kodu z sekcją kontrolki<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>
Ten kod dodaje kluczowe elementy interfejsu użytkownika. Metody i obiekty obsługujące funkcje elementów interfejsu użytkownika są zdefiniowane w pliku MainWindow.xaml.cs tworzonym w następnym kroku.
- Przycisk, który loguje użytkownika.
SignInButton_Click
metoda jest wywoływana, gdy użytkownik wybierze ten przycisk. - Przycisk, który powoduje wylogowanie użytkownika.
SignOutButton_Click
metoda jest wywoływana, gdy użytkownik wybierze ten przycisk. - Pole tekstowe, które wyświetla szczegóły wyniku uwierzytelniania po próbie zalogowania się przez użytkownika. Wyświetlane tutaj informacje są zwracane przez
ResultText
obiekt. - Pole tekstowe, które wyświetla szczegóły tokenu po pomyślnym zalogowaniu użytkownika. Wyświetlane tutaj informacje są zwracane przez
TokenInfoText
obiekt.
Dodawanie kodu do pliku MainWindow.xaml.cs
Plik MainWindow.xaml.cs zawiera kod, który zapewnia logikę wykonywania dla zachowania elementów interfejsu, które znajdują się w pliku MainWindow.xaml.
Otwórz plik MainWindow.xaml.cs w folderze głównym aplikacji.
Dodaj następujący kod w pliku w celu zaimportowania pakietów i zdefiniuj symbole zastępcze dla tworzonych metod.
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){...} } }
Dodaj następujący kod do metody
SignInButton_Click
: Ta metoda jest wywoływana, gdy użytkownik wybierze przycisk Zaloguj się .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()
Zwraca wszystkie dostępne konta w pamięci podręcznej tokenu użytkownika dla aplikacji. InterfejsIAccount
reprezentuje informacje o pojedynczym koncie.Aby uzyskać tokeny, aplikacja próbuje uzyskać token dyskretnie przy użyciu
AcquireTokenSilent
metody w celu sprawdzenia, czy akceptowalny token znajduje się w pamięci podręcznej. MetodaAcquireTokenSilent
może zakończyć się niepowodzeniem, na przykład dlatego, że użytkownik wylogował się. Gdy biblioteka MSAL wykryje, że problem można rozwiązać, wymagając interaktywnej akcji, zgłasza wyjątekMsalUiRequiredException
. Ten wyjątek powoduje, że aplikacja uzyskuje token interaktywnie.AcquireTokenInteractive
Wywołanie metody powoduje wyświetlenie okna z monitem o zalogowanie użytkowników. Aplikacje zwykle wymagają, aby użytkownicy logowali się interaktywnie przy pierwszym uwierzytelnieniu. Konieczne może być także zalogowanie się podczas cichej operacji uzyskania tokenu. Po tym jakAcquireTokenInteractive
zostanie wykonane po raz pierwszy,AcquireTokenSilent
staje się standardową metodą uzyskiwania tokenów.Dodaj następujący kod do metody
SignOutButton_Click
: Ta metoda jest wywoływana, gdy użytkownik wybierze przycisk Wyloguj.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
usuwa pamięć podręczną wszystkich kont i wszystkich odpowiednich tokenów dostępu. Następnym razem, gdy użytkownik spróbuje się zalogować, będzie musiał to zrobić interaktywnie.Dodaj następujący kod do metody
DisplayBasicTokenInfo
: Ta metoda wyświetla podstawowe informacje o tokenie.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; } }
Dodawanie kodu do pliku App.xaml.cs
App.xaml to miejsce, w którym deklarujesz zasoby używane w całej aplikacji. Jest to punkt wejścia aplikacji. App.xaml.cs jest kodem stojącym za plikiem app.xaml. App.xaml.cs również definiuje okno uruchamiania aplikacji.
Otwórz plik App.xaml.cs w folderze głównym aplikacji, a następnie dodaj do niego następujący kod.
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; } }
}
}
W tym kroku załadujesz plik appsettings.json . Konstruktor konfiguracji ułatwia odczytywanie konfiguracji aplikacji zdefiniowanych w pliku appsettings.json . Aplikację WPF można również zdefiniować jako publiczną aplikację kliencką, ponieważ jest to aplikacja desktopowa. Metoda TokenCacheHelper.EnableSerialization
umożliwia serializację pamięci podręcznej tokenów.
Uruchom aplikację
Uruchamianie aplikacji i logowanie się w celu przetestowania aplikacji
W terminalu przejdź do folderu głównego aplikacji WPF i uruchom aplikację, uruchamiając polecenie
dotnet run
w terminalu.Po uruchomieniu przykładu powinno zostać wyświetlone okno z przyciskiem Zaloguj się. Wybierz przycisk Zaloguj się.
Na stronie logowania wprowadź swój adres e-mail konta. Jeśli nie masz konta, wybierz pozycję Nie masz konta? Załóż konto, co uruchamia proces rejestracji. Wykonaj czynności opisane w tym przepływie, aby utworzyć nowe konto i zalogować się.
Po zalogowaniu zobaczysz ekran pokazujący pomyślne logowanie oraz podstawowe informacje o koncie użytkownika przechowywane w pobranym tokenie. Podstawowe informacje są wyświetlane w sekcji Informacje o tokenie na ekranie logowania