Update MsalProvider to use native account broker (#169)
* Updated MsalProvider to use local account broker when possible. * Updated MsalProvider configuration to support toggling org account login. * Re-adding SDK version header logic * Added token cache example to wpf sample app. * Renamed WpfMsalProviderSample to WpfNet5WindowsMsalProviderSample and added WpfNetCoreMsalProviderSample
This commit is contained in:
Родитель
69197dd945
Коммит
33f781a577
|
@ -1,8 +1,10 @@
|
||||||
<Project Sdk="Microsoft.NET.Sdk">
|
<Project Sdk="MSBuild.Sdk.Extras">
|
||||||
|
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
<TargetFramework>netstandard2.0</TargetFramework>
|
<TargetFrameworks>netstandard2.0;uap10.0;net5.0-windows10.0.17763.0;netcoreapp3.1</TargetFrameworks>
|
||||||
|
<TargetPlatformMinVersion>10.0.17763.0</TargetPlatformMinVersion>
|
||||||
|
<SupportedOSPlatformVersion>7</SupportedOSPlatformVersion>
|
||||||
|
|
||||||
<Title>Windows Community Toolkit .NET Standard Auth Services</Title>
|
<Title>Windows Community Toolkit .NET Standard Auth Services</Title>
|
||||||
<Description>
|
<Description>
|
||||||
This library provides an authentication provider based on the native Windows dialogues. It is part of the Windows Community Toolkit.
|
This library provides an authentication provider based on the native Windows dialogues. It is part of the Windows Community Toolkit.
|
||||||
|
@ -18,6 +20,10 @@
|
||||||
<PackageReference Include="Microsoft.Identity.Client.Extensions.Msal" Version="2.19.1" />
|
<PackageReference Include="Microsoft.Identity.Client.Extensions.Msal" Version="2.19.1" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup Condition="'$(TargetFramework)' == 'netcoreapp3.1'">
|
||||||
|
<PackageReference Include="Microsoft.Identity.Client.Desktop" Version="4.37.0" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\CommunityToolkit.Authentication\CommunityToolkit.Authentication.csproj" />
|
<ProjectReference Include="..\CommunityToolkit.Authentication\CommunityToolkit.Authentication.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
|
@ -2,6 +2,7 @@
|
||||||
// The .NET Foundation licenses this file to you under the MIT license.
|
// The .NET Foundation licenses this file to you under the MIT license.
|
||||||
// See the LICENSE file in the project root for more information.
|
// See the LICENSE file in the project root for more information.
|
||||||
|
|
||||||
|
using System;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
using System.Net.Http.Headers;
|
using System.Net.Http.Headers;
|
||||||
|
@ -11,6 +12,16 @@ using System.Threading.Tasks;
|
||||||
using Microsoft.Graph;
|
using Microsoft.Graph;
|
||||||
using Microsoft.Identity.Client;
|
using Microsoft.Identity.Client;
|
||||||
|
|
||||||
|
#if WINDOWS_UWP
|
||||||
|
using Windows.Security.Authentication.Web;
|
||||||
|
#else
|
||||||
|
using System.Diagnostics;
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if NETCOREAPP3_1
|
||||||
|
using Microsoft.Identity.Client.Desktop;
|
||||||
|
#endif
|
||||||
|
|
||||||
namespace CommunityToolkit.Authentication
|
namespace CommunityToolkit.Authentication
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
@ -18,52 +29,73 @@ namespace CommunityToolkit.Authentication
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class MsalProvider : BaseProvider
|
public class MsalProvider : BaseProvider
|
||||||
{
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A prefix value used to create the redirect URI value for use in AAD.
|
||||||
|
/// </summary>
|
||||||
|
public static readonly string MSAccountBrokerRedirectUriPrefix = "ms-appx-web://microsoft.aad.brokerplugin/";
|
||||||
|
|
||||||
private static readonly SemaphoreSlim SemaphoreSlim = new (1);
|
private static readonly SemaphoreSlim SemaphoreSlim = new (1);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Gets or sets the currently authenticated user account.
|
||||||
|
/// </summary>
|
||||||
|
public IAccount Account { get; protected set; }
|
||||||
|
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override string CurrentAccountId => _account?.HomeAccountId?.Identifier;
|
public override string CurrentAccountId => Account?.HomeAccountId?.Identifier;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets the MSAL.NET Client used to authenticate the user.
|
/// Gets or sets the MSAL.NET Client used to authenticate the user.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected IPublicClientApplication Client { get; private set; }
|
public IPublicClientApplication Client { get; protected set; }
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Gets an array of scopes to use for accessing Graph resources.
|
/// Gets an array of scopes to use for accessing Graph resources.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
protected string[] Scopes { get; private set; }
|
protected string[] Scopes { get; }
|
||||||
|
|
||||||
private IAccount _account;
|
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Initializes a new instance of the <see cref="MsalProvider"/> class.
|
/// Initializes a new instance of the <see cref="MsalProvider"/> class using a configuration object.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="clientId">Registered ClientId.</param>
|
/// <param name="client">Registered ClientId in Azure Acitve Directory.</param>
|
||||||
/// <param name="redirectUri">RedirectUri for auth response.</param>
|
|
||||||
/// <param name="scopes">List of Scopes to initially request.</param>
|
/// <param name="scopes">List of Scopes to initially request.</param>
|
||||||
/// <param name="autoSignIn">Determines whether the provider attempts to silently log in upon instantionation.</param>
|
/// <param name="autoSignIn">Determines whether the provider attempts to silently log in upon creation.</param>
|
||||||
public MsalProvider(string clientId, string[] scopes = null, string redirectUri = "https://login.microsoftonline.com/common/oauth2/nativeclient", bool autoSignIn = true)
|
public MsalProvider(IPublicClientApplication client, string[] scopes = null, bool autoSignIn = true)
|
||||||
{
|
{
|
||||||
var client = PublicClientApplicationBuilder.Create(clientId)
|
|
||||||
.WithAuthority(AzureCloudInstance.AzurePublic, AadAuthorityAudience.AzureAdAndPersonalMicrosoftAccount)
|
|
||||||
.WithRedirectUri(redirectUri)
|
|
||||||
.WithClientName(ProviderManager.ClientName)
|
|
||||||
.WithClientVersion(Assembly.GetExecutingAssembly().GetName().Version.ToString())
|
|
||||||
.Build();
|
|
||||||
|
|
||||||
Scopes = scopes.Select(s => s.ToLower()).ToArray() ?? new string[] { string.Empty };
|
|
||||||
|
|
||||||
Client = client;
|
Client = client;
|
||||||
|
Scopes = scopes.Select(s => s.ToLower()).ToArray() ?? new string[] { string.Empty };
|
||||||
|
|
||||||
if (autoSignIn)
|
if (autoSignIn)
|
||||||
{
|
{
|
||||||
_ = TrySilentSignInAsync();
|
TrySilentSignInAsync();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Initializes a new instance of the <see cref="MsalProvider"/> class with default configuration values.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="clientId">Registered client id in Azure Acitve Directory.</param>
|
||||||
|
/// <param name="redirectUri">RedirectUri for auth response.</param>
|
||||||
|
/// <param name="scopes">List of Scopes to initially request.</param>
|
||||||
|
/// <param name="autoSignIn">Determines whether the provider attempts to silently log in upon creation.</param>
|
||||||
|
/// <param name="listWindowsWorkAndSchoolAccounts">Determines if organizational accounts should be enabled/disabled.</param>
|
||||||
|
/// <param name="tenantId">Registered tenant id in Azure Active Directory.</param>
|
||||||
|
public MsalProvider(string clientId, string[] scopes = null, string redirectUri = null, bool autoSignIn = true, bool listWindowsWorkAndSchoolAccounts = true, string tenantId = null)
|
||||||
|
{
|
||||||
|
Client = CreatePublicClientApplication(clientId, tenantId, redirectUri, listWindowsWorkAndSchoolAccounts);
|
||||||
|
Scopes = scopes.Select(s => s.ToLower()).ToArray() ?? new string[] { string.Empty };
|
||||||
|
|
||||||
|
if (autoSignIn)
|
||||||
|
{
|
||||||
|
TrySilentSignInAsync();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public override async Task AuthenticateRequestAsync(HttpRequestMessage request)
|
public override async Task AuthenticateRequestAsync(HttpRequestMessage request)
|
||||||
{
|
{
|
||||||
|
AddSdkVersion(request);
|
||||||
|
|
||||||
string token;
|
string token;
|
||||||
|
|
||||||
// Check if any specific scopes are being requested.
|
// Check if any specific scopes are being requested.
|
||||||
|
@ -87,7 +119,7 @@ namespace CommunityToolkit.Authentication
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public override async Task<bool> TrySilentSignInAsync()
|
public override async Task<bool> TrySilentSignInAsync()
|
||||||
{
|
{
|
||||||
if (_account != null && State == ProviderState.SignedIn)
|
if (Account != null && State == ProviderState.SignedIn)
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -108,7 +140,7 @@ namespace CommunityToolkit.Authentication
|
||||||
/// <inheritdoc/>
|
/// <inheritdoc/>
|
||||||
public override async Task SignInAsync()
|
public override async Task SignInAsync()
|
||||||
{
|
{
|
||||||
if (_account != null || State != ProviderState.SignedOut)
|
if (Account != null || State != ProviderState.SignedOut)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -129,10 +161,10 @@ namespace CommunityToolkit.Authentication
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override async Task SignOutAsync()
|
public override async Task SignOutAsync()
|
||||||
{
|
{
|
||||||
if (_account != null)
|
if (Account != null)
|
||||||
{
|
{
|
||||||
await Client.RemoveAsync(_account);
|
await Client.RemoveAsync(Account);
|
||||||
_account = null;
|
Account = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
State = ProviderState.SignedOut;
|
State = ProviderState.SignedOut;
|
||||||
|
@ -144,7 +176,48 @@ namespace CommunityToolkit.Authentication
|
||||||
return this.GetTokenWithScopesAsync(Scopes, silentOnly);
|
return this.GetTokenWithScopesAsync(Scopes, silentOnly);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async Task<string> GetTokenWithScopesAsync(string[] scopes, bool silentOnly = false)
|
/// <summary>
|
||||||
|
/// Create an instance of <see cref="PublicClientApplication"/> using the provided config and some default values.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="clientId">Registered ClientId.</param>
|
||||||
|
/// <param name="tenantId">An optional tenant id.</param>
|
||||||
|
/// <param name="redirectUri">Redirect uri for auth response.</param>
|
||||||
|
/// <param name="listWindowsWorkAndSchoolAccounts">Determines if organizational accounts should be supported.</param>
|
||||||
|
/// <returns>A new instance of <see cref="PublicClientApplication"/>.</returns>
|
||||||
|
protected IPublicClientApplication CreatePublicClientApplication(string clientId, string tenantId, string redirectUri, bool listWindowsWorkAndSchoolAccounts)
|
||||||
|
{
|
||||||
|
var authority = listWindowsWorkAndSchoolAccounts ? AadAuthorityAudience.AzureAdAndPersonalMicrosoftAccount : AadAuthorityAudience.PersonalMicrosoftAccount;
|
||||||
|
|
||||||
|
var clientBuilder = PublicClientApplicationBuilder.Create(clientId)
|
||||||
|
.WithAuthority(AzureCloudInstance.AzurePublic, authority)
|
||||||
|
.WithClientName(ProviderManager.ClientName)
|
||||||
|
.WithClientVersion(Assembly.GetExecutingAssembly().GetName().Version.ToString());
|
||||||
|
|
||||||
|
if (tenantId != null)
|
||||||
|
{
|
||||||
|
clientBuilder = clientBuilder.WithTenantId(tenantId);
|
||||||
|
}
|
||||||
|
|
||||||
|
#if WINDOWS_UWP || NET5_0_WINDOWS10_0_17763_0
|
||||||
|
clientBuilder = clientBuilder.WithBroker();
|
||||||
|
#elif NETCOREAPP3_1
|
||||||
|
clientBuilder = clientBuilder.WithWindowsBroker();
|
||||||
|
#endif
|
||||||
|
|
||||||
|
clientBuilder = (redirectUri != null)
|
||||||
|
? clientBuilder.WithRedirectUri(redirectUri)
|
||||||
|
: clientBuilder.WithDefaultRedirectUri();
|
||||||
|
|
||||||
|
return clientBuilder.Build();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Retrieve an authorization token using the provided scopes.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="scopes">An array of scopes to pass along with the Graph request.</param>
|
||||||
|
/// <param name="silentOnly">A value to determine whether account broker UI should be shown, if required by MSAL.</param>
|
||||||
|
/// <returns>A <see cref="Task"/> representing the result of the asynchronous operation.</returns>
|
||||||
|
protected async Task<string> GetTokenWithScopesAsync(string[] scopes, bool silentOnly = false)
|
||||||
{
|
{
|
||||||
await SemaphoreSlim.WaitAsync();
|
await SemaphoreSlim.WaitAsync();
|
||||||
|
|
||||||
|
@ -153,7 +226,7 @@ namespace CommunityToolkit.Authentication
|
||||||
AuthenticationResult authResult = null;
|
AuthenticationResult authResult = null;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var account = _account ?? (await Client.GetAccountsAsync()).FirstOrDefault();
|
var account = Account ?? (await Client.GetAccountsAsync()).FirstOrDefault();
|
||||||
if (account != null)
|
if (account != null)
|
||||||
{
|
{
|
||||||
authResult = await Client.AcquireTokenSilent(scopes, account).ExecuteAsync();
|
authResult = await Client.AcquireTokenSilent(scopes, account).ExecuteAsync();
|
||||||
|
@ -172,14 +245,26 @@ namespace CommunityToolkit.Authentication
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (_account != null)
|
var paramBuilder = Client.AcquireTokenInteractive(scopes);
|
||||||
|
|
||||||
|
if (Account != null)
|
||||||
{
|
{
|
||||||
authResult = await Client.AcquireTokenInteractive(scopes).WithPrompt(Prompt.NoPrompt).WithAccount(_account).ExecuteAsync();
|
paramBuilder = paramBuilder.WithAccount(Account);
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
authResult = await Client.AcquireTokenInteractive(scopes).WithPrompt(Prompt.NoPrompt).ExecuteAsync();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#if WINDOWS_UWP
|
||||||
|
// For UWP, specify NoPrompt for the least intrusive user experience.
|
||||||
|
paramBuilder = paramBuilder.WithPrompt(Prompt.NoPrompt);
|
||||||
|
#else
|
||||||
|
// Otherwise, get the process by FriendlyName from Application Domain
|
||||||
|
var friendlyName = AppDomain.CurrentDomain.FriendlyName;
|
||||||
|
var proc = Process.GetProcessesByName(friendlyName).First();
|
||||||
|
|
||||||
|
var windowHandle = proc.MainWindowHandle;
|
||||||
|
paramBuilder = paramBuilder.WithParentActivityOrWindow(windowHandle);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
authResult = await paramBuilder.ExecuteAsync();
|
||||||
}
|
}
|
||||||
catch
|
catch
|
||||||
{
|
{
|
||||||
|
@ -188,7 +273,7 @@ namespace CommunityToolkit.Authentication
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
_account = authResult?.Account;
|
Account = authResult?.Account;
|
||||||
|
|
||||||
return authResult?.AccessToken;
|
return authResult?.AccessToken;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,35 @@
|
||||||
|
// Licensed to the .NET Foundation under one or more agreements.
|
||||||
|
// The .NET Foundation licenses this file to you under the MIT license.
|
||||||
|
// See the LICENSE file in the project root for more information.
|
||||||
|
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using Microsoft.Identity.Client.Extensions.Msal;
|
||||||
|
|
||||||
|
namespace CommunityToolkit.Authentication.Extensions
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Helpers for working with the MsalProvider.
|
||||||
|
/// </summary>
|
||||||
|
public static class MsalProviderExtensions
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// Helper function to initialize the token cache for non-UWP apps. MSAL handles this automatically on UWP.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="provider">The instance of <see cref="MsalProvider"/> to init the cache for.</param>
|
||||||
|
/// <param name="storageProperties">Properties for configuring the storage cache.</param>
|
||||||
|
/// <param name="logger">Passing null uses the default TraceSource logger.</param>
|
||||||
|
/// <returns>A <see cref="Task"/> representing the result of the asynchronous operation.</returns>
|
||||||
|
public static async Task InitTokenCacheAsync(
|
||||||
|
this MsalProvider provider,
|
||||||
|
StorageCreationProperties storageProperties,
|
||||||
|
TraceSource logger = null)
|
||||||
|
{
|
||||||
|
#if !WINDOWS_UWP
|
||||||
|
// Token cache persistence (not required on UWP as MSAL does it for you)
|
||||||
|
var cacheHelper = await MsalCacheHelper.CreateAsync(storageProperties, logger);
|
||||||
|
cacheHelper.RegisterCache(provider.Client.UserTokenCache);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -110,6 +110,8 @@ namespace CommunityToolkit.Authentication
|
||||||
/// <inheritdoc />
|
/// <inheritdoc />
|
||||||
public override async Task AuthenticateRequestAsync(HttpRequestMessage request)
|
public override async Task AuthenticateRequestAsync(HttpRequestMessage request)
|
||||||
{
|
{
|
||||||
|
AddSdkVersion(request);
|
||||||
|
|
||||||
string token = await GetTokenAsync();
|
string token = await GetTokenAsync();
|
||||||
request.Headers.Authorization = new AuthenticationHeaderValue(AuthenticationHeaderScheme, token);
|
request.Headers.Authorization = new AuthenticationHeaderValue(AuthenticationHeaderScheme, token);
|
||||||
}
|
}
|
||||||
|
|
|
@ -71,7 +71,7 @@ namespace CommunityToolkit.Graph.Extensions
|
||||||
.Photo
|
.Photo
|
||||||
.Content
|
.Content
|
||||||
.Request()
|
.Request()
|
||||||
.WithScopes(new string[] { "user.readbasic.all" })
|
.WithScopes(new string[] { "user.read" })
|
||||||
.GetAsync();
|
.GetAsync();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -155,7 +155,6 @@
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Content Include="Assets\FileIcon.png" />
|
<Content Include="Assets\FileIcon.png" />
|
||||||
<None Include="Package.StoreAssociation.xml" />
|
|
||||||
<Content Include="Properties\Default.rd.xml" />
|
<Content Include="Properties\Default.rd.xml" />
|
||||||
<Content Include="Assets\LockScreenLogo.scale-200.png" />
|
<Content Include="Assets\LockScreenLogo.scale-200.png" />
|
||||||
<Content Include="Assets\SplashScreen.scale-200.png" />
|
<Content Include="Assets\SplashScreen.scale-200.png" />
|
||||||
|
|
|
@ -1,26 +0,0 @@
|
||||||
// Licensed to the .NET Foundation under one or more agreements.
|
|
||||||
// The .NET Foundation licenses this file to you under the MIT license.
|
|
||||||
// See the LICENSE file in the project root for more information.
|
|
||||||
|
|
||||||
using CommunityToolkit.Authentication;
|
|
||||||
using System;
|
|
||||||
using System.Windows;
|
|
||||||
|
|
||||||
namespace WpfMsalProviderSample
|
|
||||||
{
|
|
||||||
public partial class App : Application
|
|
||||||
{
|
|
||||||
protected override void OnActivated(EventArgs e)
|
|
||||||
{
|
|
||||||
if (ProviderManager.Instance.GlobalProvider == null)
|
|
||||||
{
|
|
||||||
string clientId = "YOUR-CLIENT-ID-HERE";
|
|
||||||
string[] scopes = new string[] { "User.Read" };
|
|
||||||
string redirectUri = "http://localhost";
|
|
||||||
ProviderManager.Instance.GlobalProvider = new MsalProvider(clientId, scopes, redirectUri);
|
|
||||||
}
|
|
||||||
|
|
||||||
base.OnActivated(e);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -0,0 +1,9 @@
|
||||||
|
<Application x:Class="WpfNet5WindowsMsalProviderSample.App"
|
||||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:local="clr-namespace:WpfNet5WindowsMsalProviderSample"
|
||||||
|
StartupUri="MainWindow.xaml">
|
||||||
|
<Application.Resources>
|
||||||
|
|
||||||
|
</Application.Resources>
|
||||||
|
</Application>
|
|
@ -0,0 +1,51 @@
|
||||||
|
// Licensed to the .NET Foundation under one or more agreements.
|
||||||
|
// The .NET Foundation licenses this file to you under the MIT license.
|
||||||
|
// See the LICENSE file in the project root for more information.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Windows;
|
||||||
|
using CommunityToolkit.Authentication;
|
||||||
|
using CommunityToolkit.Authentication.Extensions;
|
||||||
|
using Microsoft.Identity.Client.Extensions.Msal;
|
||||||
|
|
||||||
|
namespace WpfNet5WindowsMsalProviderSample
|
||||||
|
{
|
||||||
|
public partial class App : Application
|
||||||
|
{
|
||||||
|
static readonly string ClientId = "YOUR-CLIENT-ID-HERE";
|
||||||
|
static readonly string[] Scopes = new string[] { "User.Read" };
|
||||||
|
|
||||||
|
protected override void OnActivated(EventArgs e)
|
||||||
|
{
|
||||||
|
InitializeGlobalProviderAsync();
|
||||||
|
base.OnActivated(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task InitializeGlobalProviderAsync()
|
||||||
|
{
|
||||||
|
if (ProviderManager.Instance.GlobalProvider == null)
|
||||||
|
{
|
||||||
|
var provider = new MsalProvider(ClientId, Scopes, null, false, true);
|
||||||
|
|
||||||
|
// Configure the token cache storage for non-UWP applications.
|
||||||
|
var storageProperties = new StorageCreationPropertiesBuilder(CacheConfig.CacheFileName, CacheConfig.CacheDir)
|
||||||
|
.WithLinuxKeyring(
|
||||||
|
CacheConfig.LinuxKeyRingSchema,
|
||||||
|
CacheConfig.LinuxKeyRingCollection,
|
||||||
|
CacheConfig.LinuxKeyRingLabel,
|
||||||
|
CacheConfig.LinuxKeyRingAttr1,
|
||||||
|
CacheConfig.LinuxKeyRingAttr2)
|
||||||
|
.WithMacKeyChain(
|
||||||
|
CacheConfig.KeyChainServiceName,
|
||||||
|
CacheConfig.KeyChainAccountName)
|
||||||
|
.Build();
|
||||||
|
await provider.InitTokenCacheAsync(storageProperties);
|
||||||
|
|
||||||
|
ProviderManager.Instance.GlobalProvider = provider;
|
||||||
|
|
||||||
|
await provider.TrySilentSignInAsync();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,27 @@
|
||||||
|
// Licensed to the .NET Foundation under one or more agreements.
|
||||||
|
// The .NET Foundation licenses this file to you under the MIT license.
|
||||||
|
// See the LICENSE file in the project root for more information.
|
||||||
|
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Microsoft.Identity.Client.Extensions.Msal;
|
||||||
|
|
||||||
|
namespace WpfNet5WindowsMsalProviderSample
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// https://github.com/AzureAD/microsoft-authentication-extensions-for-dotnet/wiki/Cross-platform-Token-Cache
|
||||||
|
/// </summary>
|
||||||
|
class CacheConfig
|
||||||
|
{
|
||||||
|
public const string CacheFileName = "msal_cache.dat";
|
||||||
|
public const string CacheDir = "MSAL_CACHE";
|
||||||
|
|
||||||
|
public const string KeyChainServiceName = "msal_service";
|
||||||
|
public const string KeyChainAccountName = "msal_account";
|
||||||
|
|
||||||
|
public const string LinuxKeyRingSchema = "com.contoso.devtools.tokencache";
|
||||||
|
public const string LinuxKeyRingCollection = MsalCacheHelper.LinuxKeyRingDefaultCollection;
|
||||||
|
public const string LinuxKeyRingLabel = "MSAL token cache for all Contoso dev tool apps.";
|
||||||
|
public static readonly KeyValuePair<string, string> LinuxKeyRingAttr1 = new KeyValuePair<string, string>("Version", "1");
|
||||||
|
public static readonly KeyValuePair<string, string> LinuxKeyRingAttr2 = new KeyValuePair<string, string>("ProductGroup", "MyApps");
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,14 @@
|
||||||
|
<UserControl x:Class="WpfNet5WindowsMsalProviderSample.LoginButton"
|
||||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:local="clr-namespace:WpfNet5WindowsMsalProviderSample"
|
||||||
|
mc:Ignorable="d"
|
||||||
|
DataContext="{Binding RelativeSource={RelativeSource Self}}">
|
||||||
|
<Grid>
|
||||||
|
<Button x:Name="MyButton"
|
||||||
|
Click="MyButton_Click"
|
||||||
|
IsEnabled="{Binding IsEnabled}" />
|
||||||
|
</Grid>
|
||||||
|
</UserControl>
|
|
@ -0,0 +1,70 @@
|
||||||
|
// Licensed to the .NET Foundation under one or more agreements.
|
||||||
|
// The .NET Foundation licenses this file to you under the MIT license.
|
||||||
|
// See the LICENSE file in the project root for more information.
|
||||||
|
|
||||||
|
using CommunityToolkit.Authentication;
|
||||||
|
using System;
|
||||||
|
using System.Windows;
|
||||||
|
using System.Windows.Controls;
|
||||||
|
|
||||||
|
namespace WpfNet5WindowsMsalProviderSample
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// A simple button for triggering the globally configured IProvider to sign in and out.
|
||||||
|
/// </summary>
|
||||||
|
public partial class LoginButton : UserControl
|
||||||
|
{
|
||||||
|
public LoginButton()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
|
||||||
|
ProviderManager.Instance.ProviderStateChanged += (s, e) => UpdateState();
|
||||||
|
UpdateState();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void UpdateState()
|
||||||
|
{
|
||||||
|
var provider = ProviderManager.Instance.GlobalProvider;
|
||||||
|
if (provider == null || provider.State == ProviderState.Loading)
|
||||||
|
{
|
||||||
|
MyButton.Content = "Sign in";
|
||||||
|
IsEnabled = false;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (provider.State)
|
||||||
|
{
|
||||||
|
case ProviderState.SignedIn:
|
||||||
|
MyButton.Content = "Sign out";
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ProviderState.SignedOut:
|
||||||
|
MyButton.Content = "Sign in";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
IsEnabled = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void MyButton_Click(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
Application.Current.Dispatcher.Invoke(new Action(() =>
|
||||||
|
{
|
||||||
|
var provider = ProviderManager.Instance.GlobalProvider;
|
||||||
|
if (provider != null)
|
||||||
|
{
|
||||||
|
switch (provider.State)
|
||||||
|
{
|
||||||
|
case ProviderState.SignedOut:
|
||||||
|
provider.SignInAsync();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case ProviderState.SignedIn:
|
||||||
|
provider.SignOutAsync();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,13 @@
|
||||||
|
<Window x:Class="WpfNet5WindowsMsalProviderSample.MainWindow"
|
||||||
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
|
xmlns:local="clr-namespace:WpfNet5WindowsMsalProviderSample"
|
||||||
|
mc:Ignorable="d"
|
||||||
|
Title="MainWindow" Height="450" Width="800">
|
||||||
|
<StackPanel>
|
||||||
|
<local:LoginButton />
|
||||||
|
<TextBlock x:Name="SignedInUserTextBlock" />
|
||||||
|
</StackPanel>
|
||||||
|
</Window>
|
|
@ -6,7 +6,7 @@ using CommunityToolkit.Authentication;
|
||||||
using CommunityToolkit.Graph.Extensions;
|
using CommunityToolkit.Graph.Extensions;
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
|
|
||||||
namespace WpfMsalProviderSample
|
namespace WpfNet5WindowsMsalProviderSample
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Interaction logic for MainWindow.xaml
|
/// Interaction logic for MainWindow.xaml
|
|
@ -0,0 +1,19 @@
|
||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<OutputType>WinExe</OutputType>
|
||||||
|
<TargetFramework>net5.0-windows10.0.17763.0</TargetFramework>
|
||||||
|
<UseWPF>true</UseWPF>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<PackageReference Include="Microsoft.Identity.Client.Extensions.Msal" Version="2.19.2" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\..\CommunityToolkit.Authentication\CommunityToolkit.Authentication.csproj" />
|
||||||
|
<ProjectReference Include="..\..\CommunityToolkit.Authentication.Msal\CommunityToolkit.Authentication.Msal.csproj" />
|
||||||
|
<ProjectReference Include="..\..\CommunityToolkit.Graph\CommunityToolkit.Graph.csproj" />
|
||||||
|
</ItemGroup>
|
||||||
|
|
||||||
|
</Project>
|
|
@ -1,7 +1,7 @@
|
||||||
<Application x:Class="WpfMsalProviderSample.App"
|
<Application x:Class="WpfNetCoreMsalProviderSample.App"
|
||||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:local="clr-namespace:WpfMsalProviderSample"
|
xmlns:local="clr-namespace:WpfNetCoreMsalProviderSample"
|
||||||
StartupUri="MainWindow.xaml">
|
StartupUri="MainWindow.xaml">
|
||||||
<Application.Resources>
|
<Application.Resources>
|
||||||
|
|
|
@ -0,0 +1,51 @@
|
||||||
|
// Licensed to the .NET Foundation under one or more agreements.
|
||||||
|
// The .NET Foundation licenses this file to you under the MIT license.
|
||||||
|
// See the LICENSE file in the project root for more information.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Windows;
|
||||||
|
using CommunityToolkit.Authentication;
|
||||||
|
using CommunityToolkit.Authentication.Extensions;
|
||||||
|
using Microsoft.Identity.Client.Extensions.Msal;
|
||||||
|
|
||||||
|
namespace WpfNetCoreMsalProviderSample
|
||||||
|
{
|
||||||
|
public partial class App : Application
|
||||||
|
{
|
||||||
|
static readonly string ClientId = "YOUR-CLIENT-ID-HERE";
|
||||||
|
static readonly string[] Scopes = new string[] { "User.Read" };
|
||||||
|
|
||||||
|
protected override void OnActivated(EventArgs e)
|
||||||
|
{
|
||||||
|
InitializeGlobalProviderAsync();
|
||||||
|
base.OnActivated(e);
|
||||||
|
}
|
||||||
|
|
||||||
|
private async Task InitializeGlobalProviderAsync()
|
||||||
|
{
|
||||||
|
if (ProviderManager.Instance.GlobalProvider == null)
|
||||||
|
{
|
||||||
|
var provider = new MsalProvider(ClientId, Scopes, null, false, true);
|
||||||
|
|
||||||
|
// Configure the token cache storage for non-UWP applications.
|
||||||
|
var storageProperties = new StorageCreationPropertiesBuilder(CacheConfig.CacheFileName, CacheConfig.CacheDir)
|
||||||
|
.WithLinuxKeyring(
|
||||||
|
CacheConfig.LinuxKeyRingSchema,
|
||||||
|
CacheConfig.LinuxKeyRingCollection,
|
||||||
|
CacheConfig.LinuxKeyRingLabel,
|
||||||
|
CacheConfig.LinuxKeyRingAttr1,
|
||||||
|
CacheConfig.LinuxKeyRingAttr2)
|
||||||
|
.WithMacKeyChain(
|
||||||
|
CacheConfig.KeyChainServiceName,
|
||||||
|
CacheConfig.KeyChainAccountName)
|
||||||
|
.Build();
|
||||||
|
await provider.InitTokenCacheAsync(storageProperties);
|
||||||
|
|
||||||
|
ProviderManager.Instance.GlobalProvider = provider;
|
||||||
|
|
||||||
|
await provider.TrySilentSignInAsync();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,14 @@
|
||||||
|
// Licensed to the .NET Foundation under one or more agreements.
|
||||||
|
// The .NET Foundation licenses this file to you under the MIT license.
|
||||||
|
// See the LICENSE file in the project root for more information.
|
||||||
|
|
||||||
|
using System.Windows;
|
||||||
|
|
||||||
|
[assembly: ThemeInfo(
|
||||||
|
ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
|
||||||
|
//(used if a resource is not found in the page,
|
||||||
|
// or application resource dictionaries)
|
||||||
|
ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
|
||||||
|
//(used if a resource is not found in the page,
|
||||||
|
// app, or any theme specific resource dictionaries)
|
||||||
|
)]
|
|
@ -0,0 +1,27 @@
|
||||||
|
// Licensed to the .NET Foundation under one or more agreements.
|
||||||
|
// The .NET Foundation licenses this file to you under the MIT license.
|
||||||
|
// See the LICENSE file in the project root for more information.
|
||||||
|
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using Microsoft.Identity.Client.Extensions.Msal;
|
||||||
|
|
||||||
|
namespace WpfNetCoreMsalProviderSample
|
||||||
|
{
|
||||||
|
/// <summary>
|
||||||
|
/// https://github.com/AzureAD/microsoft-authentication-extensions-for-dotnet/wiki/Cross-platform-Token-Cache
|
||||||
|
/// </summary>
|
||||||
|
class CacheConfig
|
||||||
|
{
|
||||||
|
public const string CacheFileName = "msal_cache.dat";
|
||||||
|
public const string CacheDir = "MSAL_CACHE";
|
||||||
|
|
||||||
|
public const string KeyChainServiceName = "msal_service";
|
||||||
|
public const string KeyChainAccountName = "msal_account";
|
||||||
|
|
||||||
|
public const string LinuxKeyRingSchema = "com.contoso.devtools.tokencache";
|
||||||
|
public const string LinuxKeyRingCollection = MsalCacheHelper.LinuxKeyRingDefaultCollection;
|
||||||
|
public const string LinuxKeyRingLabel = "MSAL token cache for all Contoso dev tool apps.";
|
||||||
|
public static readonly KeyValuePair<string, string> LinuxKeyRingAttr1 = new KeyValuePair<string, string>("Version", "1");
|
||||||
|
public static readonly KeyValuePair<string, string> LinuxKeyRingAttr2 = new KeyValuePair<string, string>("ProductGroup", "MyApps");
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,9 +1,9 @@
|
||||||
<UserControl x:Class="WpfMsalProviderSample.LoginButton"
|
<UserControl x:Class="WpfNetCoreMsalProviderSample.LoginButton"
|
||||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
xmlns:local="clr-namespace:WpfMsalProviderSample"
|
xmlns:local="clr-namespace:WpfNetCoreMsalProviderSample"
|
||||||
mc:Ignorable="d"
|
mc:Ignorable="d"
|
||||||
DataContext="{Binding RelativeSource={RelativeSource Self}}">
|
DataContext="{Binding RelativeSource={RelativeSource Self}}">
|
||||||
<Grid>
|
<Grid>
|
|
@ -2,12 +2,12 @@
|
||||||
// The .NET Foundation licenses this file to you under the MIT license.
|
// The .NET Foundation licenses this file to you under the MIT license.
|
||||||
// See the LICENSE file in the project root for more information.
|
// See the LICENSE file in the project root for more information.
|
||||||
|
|
||||||
using CommunityToolkit.Authentication;
|
|
||||||
using System;
|
using System;
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
using System.Windows.Controls;
|
using System.Windows.Controls;
|
||||||
|
using CommunityToolkit.Authentication;
|
||||||
|
|
||||||
namespace WpfMsalProviderSample
|
namespace WpfNetCoreMsalProviderSample
|
||||||
{
|
{
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A simple button for triggering the globally configured IProvider to sign in and out.
|
/// A simple button for triggering the globally configured IProvider to sign in and out.
|
|
@ -1,9 +1,9 @@
|
||||||
<Window x:Class="WpfMsalProviderSample.MainWindow"
|
<Window x:Class="WpfNetCoreMsalProviderSample.MainWindow"
|
||||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||||
xmlns:local="clr-namespace:WpfMsalProviderSample"
|
xmlns:local="clr-namespace:WpfNetCoreMsalProviderSample"
|
||||||
mc:Ignorable="d"
|
mc:Ignorable="d"
|
||||||
Title="MainWindow" Height="450" Width="800">
|
Title="MainWindow" Height="450" Width="800">
|
||||||
<StackPanel>
|
<StackPanel>
|
|
@ -0,0 +1,37 @@
|
||||||
|
// Licensed to the .NET Foundation under one or more agreements.
|
||||||
|
// The .NET Foundation licenses this file to you under the MIT license.
|
||||||
|
// See the LICENSE file in the project root for more information.
|
||||||
|
|
||||||
|
using System.Windows;
|
||||||
|
using CommunityToolkit.Authentication;
|
||||||
|
using CommunityToolkit.Graph.Extensions;
|
||||||
|
|
||||||
|
namespace WpfNetCoreMsalProviderSample
|
||||||
|
{
|
||||||
|
public partial class MainWindow : Window
|
||||||
|
{
|
||||||
|
public MainWindow()
|
||||||
|
{
|
||||||
|
InitializeComponent();
|
||||||
|
|
||||||
|
ProviderManager.Instance.ProviderStateChanged += OnProviderStateChanged;
|
||||||
|
}
|
||||||
|
|
||||||
|
private async void OnProviderStateChanged(object sender, ProviderStateChangedEventArgs e)
|
||||||
|
{
|
||||||
|
if (e.NewState == ProviderState.SignedIn)
|
||||||
|
{
|
||||||
|
SignedInUserTextBlock.Text = "Signed in as...";
|
||||||
|
|
||||||
|
var graphClient = ProviderManager.Instance.GlobalProvider.GetClient();
|
||||||
|
var me = await graphClient.Me.Request().GetAsync();
|
||||||
|
|
||||||
|
SignedInUserTextBlock.Text = "Signed in as: " + me.DisplayName;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SignedInUserTextBlock.Text = "Please sign in.";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -4,11 +4,12 @@
|
||||||
<OutputType>WinExe</OutputType>
|
<OutputType>WinExe</OutputType>
|
||||||
<TargetFramework>netcoreapp3.1</TargetFramework>
|
<TargetFramework>netcoreapp3.1</TargetFramework>
|
||||||
<UseWPF>true</UseWPF>
|
<UseWPF>true</UseWPF>
|
||||||
|
<DeterministicSourcePaths Condition="'$(EnableSourceLink)' == ''">false</DeterministicSourcePaths>
|
||||||
</PropertyGroup>
|
</PropertyGroup>
|
||||||
|
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ProjectReference Include="..\..\CommunityToolkit.Authentication\CommunityToolkit.Authentication.csproj" />
|
|
||||||
<ProjectReference Include="..\..\CommunityToolkit.Authentication.Msal\CommunityToolkit.Authentication.Msal.csproj" />
|
<ProjectReference Include="..\..\CommunityToolkit.Authentication.Msal\CommunityToolkit.Authentication.Msal.csproj" />
|
||||||
|
<ProjectReference Include="..\..\CommunityToolkit.Authentication\CommunityToolkit.Authentication.csproj" />
|
||||||
<ProjectReference Include="..\..\CommunityToolkit.Graph\CommunityToolkit.Graph.csproj" />
|
<ProjectReference Include="..\..\CommunityToolkit.Graph\CommunityToolkit.Graph.csproj" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
|
|
@ -43,12 +43,14 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Samples", "Samples", "{022B
|
||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UwpMsalProviderSample", "Samples\UwpMsalProviderSample\UwpMsalProviderSample.csproj", "{D0F6A1EB-806E-424A-BDCA-9F749F12774F}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UwpMsalProviderSample", "Samples\UwpMsalProviderSample\UwpMsalProviderSample.csproj", "{D0F6A1EB-806E-424A-BDCA-9F749F12774F}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WpfMsalProviderSample", "Samples\WpfMsalProviderSample\WpfMsalProviderSample.csproj", "{EDAD72A8-498B-4645-AD1A-E5CDBDB610F7}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "WpfNet5WindowsMsalProviderSample", "Samples\WpfNet5WindowsMsalProviderSample\WpfNet5WindowsMsalProviderSample.csproj", "{EDAD72A8-498B-4645-AD1A-E5CDBDB610F7}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UwpWindowsProviderSample", "Samples\UwpWindowsProviderSample\UwpWindowsProviderSample.csproj", "{C60C02DF-F44C-4449-A1D4-C2DC3A7959B9}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "UwpWindowsProviderSample", "Samples\UwpWindowsProviderSample\UwpWindowsProviderSample.csproj", "{C60C02DF-F44C-4449-A1D4-C2DC3A7959B9}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ManualGraphRequestSample", "Samples\ManualGraphRequestSample\ManualGraphRequestSample.csproj", "{192CC7FD-408D-4B0B-9032-AD06C7BE46C6}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ManualGraphRequestSample", "Samples\ManualGraphRequestSample\ManualGraphRequestSample.csproj", "{192CC7FD-408D-4B0B-9032-AD06C7BE46C6}"
|
||||||
EndProject
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "WpfNetCoreMsalProviderSample", "Samples\WpfNetCoreMsalProviderSample\WpfNetCoreMsalProviderSample.csproj", "{86AD7D3C-F03F-4FD1-8D69-AB0520805A65}"
|
||||||
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
CI|Any CPU = CI|Any CPU
|
CI|Any CPU = CI|Any CPU
|
||||||
|
@ -540,6 +542,46 @@ Global
|
||||||
{192CC7FD-408D-4B0B-9032-AD06C7BE46C6}.Release|x86.ActiveCfg = Release|x86
|
{192CC7FD-408D-4B0B-9032-AD06C7BE46C6}.Release|x86.ActiveCfg = Release|x86
|
||||||
{192CC7FD-408D-4B0B-9032-AD06C7BE46C6}.Release|x86.Build.0 = Release|x86
|
{192CC7FD-408D-4B0B-9032-AD06C7BE46C6}.Release|x86.Build.0 = Release|x86
|
||||||
{192CC7FD-408D-4B0B-9032-AD06C7BE46C6}.Release|x86.Deploy.0 = Release|x86
|
{192CC7FD-408D-4B0B-9032-AD06C7BE46C6}.Release|x86.Deploy.0 = Release|x86
|
||||||
|
{86AD7D3C-F03F-4FD1-8D69-AB0520805A65}.CI|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{86AD7D3C-F03F-4FD1-8D69-AB0520805A65}.CI|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{86AD7D3C-F03F-4FD1-8D69-AB0520805A65}.CI|ARM.ActiveCfg = Debug|Any CPU
|
||||||
|
{86AD7D3C-F03F-4FD1-8D69-AB0520805A65}.CI|ARM.Build.0 = Debug|Any CPU
|
||||||
|
{86AD7D3C-F03F-4FD1-8D69-AB0520805A65}.CI|ARM64.ActiveCfg = Debug|Any CPU
|
||||||
|
{86AD7D3C-F03F-4FD1-8D69-AB0520805A65}.CI|ARM64.Build.0 = Debug|Any CPU
|
||||||
|
{86AD7D3C-F03F-4FD1-8D69-AB0520805A65}.CI|x64.ActiveCfg = Debug|Any CPU
|
||||||
|
{86AD7D3C-F03F-4FD1-8D69-AB0520805A65}.CI|x64.Build.0 = Debug|Any CPU
|
||||||
|
{86AD7D3C-F03F-4FD1-8D69-AB0520805A65}.CI|x86.ActiveCfg = Debug|Any CPU
|
||||||
|
{86AD7D3C-F03F-4FD1-8D69-AB0520805A65}.CI|x86.Build.0 = Debug|Any CPU
|
||||||
|
{86AD7D3C-F03F-4FD1-8D69-AB0520805A65}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{86AD7D3C-F03F-4FD1-8D69-AB0520805A65}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{86AD7D3C-F03F-4FD1-8D69-AB0520805A65}.Debug|ARM.ActiveCfg = Debug|Any CPU
|
||||||
|
{86AD7D3C-F03F-4FD1-8D69-AB0520805A65}.Debug|ARM.Build.0 = Debug|Any CPU
|
||||||
|
{86AD7D3C-F03F-4FD1-8D69-AB0520805A65}.Debug|ARM64.ActiveCfg = Debug|Any CPU
|
||||||
|
{86AD7D3C-F03F-4FD1-8D69-AB0520805A65}.Debug|ARM64.Build.0 = Debug|Any CPU
|
||||||
|
{86AD7D3C-F03F-4FD1-8D69-AB0520805A65}.Debug|x64.ActiveCfg = Debug|Any CPU
|
||||||
|
{86AD7D3C-F03F-4FD1-8D69-AB0520805A65}.Debug|x64.Build.0 = Debug|Any CPU
|
||||||
|
{86AD7D3C-F03F-4FD1-8D69-AB0520805A65}.Debug|x86.ActiveCfg = Debug|Any CPU
|
||||||
|
{86AD7D3C-F03F-4FD1-8D69-AB0520805A65}.Debug|x86.Build.0 = Debug|Any CPU
|
||||||
|
{86AD7D3C-F03F-4FD1-8D69-AB0520805A65}.Native|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{86AD7D3C-F03F-4FD1-8D69-AB0520805A65}.Native|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{86AD7D3C-F03F-4FD1-8D69-AB0520805A65}.Native|ARM.ActiveCfg = Debug|Any CPU
|
||||||
|
{86AD7D3C-F03F-4FD1-8D69-AB0520805A65}.Native|ARM.Build.0 = Debug|Any CPU
|
||||||
|
{86AD7D3C-F03F-4FD1-8D69-AB0520805A65}.Native|ARM64.ActiveCfg = Debug|Any CPU
|
||||||
|
{86AD7D3C-F03F-4FD1-8D69-AB0520805A65}.Native|ARM64.Build.0 = Debug|Any CPU
|
||||||
|
{86AD7D3C-F03F-4FD1-8D69-AB0520805A65}.Native|x64.ActiveCfg = Debug|Any CPU
|
||||||
|
{86AD7D3C-F03F-4FD1-8D69-AB0520805A65}.Native|x64.Build.0 = Debug|Any CPU
|
||||||
|
{86AD7D3C-F03F-4FD1-8D69-AB0520805A65}.Native|x86.ActiveCfg = Debug|Any CPU
|
||||||
|
{86AD7D3C-F03F-4FD1-8D69-AB0520805A65}.Native|x86.Build.0 = Debug|Any CPU
|
||||||
|
{86AD7D3C-F03F-4FD1-8D69-AB0520805A65}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{86AD7D3C-F03F-4FD1-8D69-AB0520805A65}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{86AD7D3C-F03F-4FD1-8D69-AB0520805A65}.Release|ARM.ActiveCfg = Release|Any CPU
|
||||||
|
{86AD7D3C-F03F-4FD1-8D69-AB0520805A65}.Release|ARM.Build.0 = Release|Any CPU
|
||||||
|
{86AD7D3C-F03F-4FD1-8D69-AB0520805A65}.Release|ARM64.ActiveCfg = Release|Any CPU
|
||||||
|
{86AD7D3C-F03F-4FD1-8D69-AB0520805A65}.Release|ARM64.Build.0 = Release|Any CPU
|
||||||
|
{86AD7D3C-F03F-4FD1-8D69-AB0520805A65}.Release|x64.ActiveCfg = Release|Any CPU
|
||||||
|
{86AD7D3C-F03F-4FD1-8D69-AB0520805A65}.Release|x64.Build.0 = Release|Any CPU
|
||||||
|
{86AD7D3C-F03F-4FD1-8D69-AB0520805A65}.Release|x86.ActiveCfg = Release|Any CPU
|
||||||
|
{86AD7D3C-F03F-4FD1-8D69-AB0520805A65}.Release|x86.Build.0 = Release|Any CPU
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
|
@ -550,6 +592,7 @@ Global
|
||||||
{EDAD72A8-498B-4645-AD1A-E5CDBDB610F7} = {022BF202-8D0D-4A6B-8A5B-92376D2EB5DA}
|
{EDAD72A8-498B-4645-AD1A-E5CDBDB610F7} = {022BF202-8D0D-4A6B-8A5B-92376D2EB5DA}
|
||||||
{C60C02DF-F44C-4449-A1D4-C2DC3A7959B9} = {022BF202-8D0D-4A6B-8A5B-92376D2EB5DA}
|
{C60C02DF-F44C-4449-A1D4-C2DC3A7959B9} = {022BF202-8D0D-4A6B-8A5B-92376D2EB5DA}
|
||||||
{192CC7FD-408D-4B0B-9032-AD06C7BE46C6} = {022BF202-8D0D-4A6B-8A5B-92376D2EB5DA}
|
{192CC7FD-408D-4B0B-9032-AD06C7BE46C6} = {022BF202-8D0D-4A6B-8A5B-92376D2EB5DA}
|
||||||
|
{86AD7D3C-F03F-4FD1-8D69-AB0520805A65} = {022BF202-8D0D-4A6B-8A5B-92376D2EB5DA}
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(ExtensibilityGlobals) = postSolution
|
GlobalSection(ExtensibilityGlobals) = postSolution
|
||||||
SolutionGuid = {20641689-5BDE-4F6F-8889-CCDD2CC2685E}
|
SolutionGuid = {20641689-5BDE-4F6F-8889-CCDD2CC2685E}
|
||||||
|
|
Загрузка…
Ссылка в новой задаче