让代码更简单

C#获取Microsoft Graph API授权及缓存管理 Token

重要:本文最后更新于2024-02-28 17:00:16,某些文章具有时效性,若有错误或已失效,请在下方留言或联系代码狗

最近在重写Microsoft Graph API使用outlook发送邮件的程序,发现Microsoft Graph API授权的Token有效期仅1小时,为了避免Token过期导致程序异常的情况,查阅官方文档后找到了解决办法。

安装NuGet 包

控制台和包管理器二选一,或者手动下载 Microsoft.Identity.Client.Extensions.Msal

复制
Microsoft.Identity.Client.Extensions.Msal

安装后引用

复制
using Microsoft.Identity.Client.Extensions.Msal;

然后使用下面的代码配置缓存,并注册缓存

复制
var storageProperties =
     new StorageCreationPropertiesBuilder(Config.CacheFileName, Config.CacheDir)
     .WithLinuxKeyring(
         Config.LinuxKeyRingSchema,
         Config.LinuxKeyRingCollection,
         Config.LinuxKeyRingLabel,
         Config.LinuxKeyRingAttr1,
         Config.LinuxKeyRingAttr2)
     .WithMacKeyChain(
         Config.KeyChainServiceName,
         Config.KeyChainAccountName)
     .Build();

 IPublicClientApplication pca = PublicClientApplicationBuilder.Create(clientId)
    .WithAuthority(Config.Authority)
    .WithRedirectUri("http://localhost")  // make sure to register this redirect URI for the interactive login 
    .Build();
    

// This hooks up the cross-platform cache into MSAL
var cacheHelper = await MsalCacheHelper.CreateAsync(storageProperties );
cacheHelper.RegisterCache(pca.UserTokenCache);

纯文本模式缓存

复制
storageProperties =
    new StorageCreationPropertiesBuilder(
        Config.CacheFileName + ".plaintext",
        Config.CacheDir)
    .WithUnprotectedFile()
    .Build();

var cacheHelper = await MsalCacheHelper.CreateAsync(storageProperties).ConfigureAwait(false);

设计到的Config.cs类代码如下

复制
internal static class Config
    {
        // App settings
        public static readonly string[] Scopes = new[] { "user.read" };

        // Use "common" if you want to allow any "enterprise" (work or school) account AND any user account (live.com, outlook, hotmail) to log in.
        // Use an actual tenant ID to allow only your enterprise to log in.
        // Use "organizations" to allow only enterprise log-in, this is required for the Username / Password flow
        public const string Authority = "https://login.microsoftonline.com/organizations";

        // DO NOT USE THIS CLIENT ID IN YOUR APP. WE REGULARLY DELETE THEM. CREATE YOUR OWN!
        public const string ClientId = "1d18b3b0-251b-4714-a02a-9956cec86c2d"; 

        // Cache settings
        public const string CacheFileName = "myapp_msal_cache.txt";
        public readonly static string CacheDir = MsalCacheHelper.UserRootDirectory;

        public const string KeyChainServiceName = "myapp_msal_service";
        public const string KeyChainAccountName = "myapp_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");



    }

授权代码如下,该代码使用了非交互式获取权限,如果不能通过非交互式获取,将会进行交互式获取。

复制
private async Task auth_()
{

    PublicClientApp = PublicClientApplicationBuilder.Create(client_id_tbx.Text)
    .WithDefaultRedirectUri()
    .WithAuthority(AzureCloudInstance.AzurePublic, "common")
    .Build();

    var cacheHelper = await MsalCacheHelper.CreateAsync(storageProperties);
    cacheHelper.RegisterCache(PublicClientApp.UserTokenCache);

    var accounts = await PublicClientApp.GetAccountsAsync();
    var firstAccount = accounts.FirstOrDefault();
    try
    {
        authResult = await PublicClientApp.AcquireTokenSilent(scopes, firstAccount)
        .ExecuteAsync();
        // authResult = await PublicClientApp.AcquireTokenInteractive(scopes).ExecuteAsync();
    }
    catch (MsalUiRequiredException ex)
    {
        // A MsalUiRequiredException happened on AcquireTokenSilent.
        // This indicates you need to call AcquireTokenInteractive to acquire a token
        System.Diagnostics.Debug.WriteLine($"MsalUiRequiredException: {ex.Message}");
        try
        {
            authResult = await PublicClientApp.AcquireTokenInteractive(scopes)
                .WithAccount(accounts.FirstOrDefault())
                .ExecuteAsync();
        }
        catch (MsalException msalex)
        {
            textBox1.AppendText(Environment.NewLine + $"Error Acquiring Token:{System.Environment.NewLine}{msalex}");
        }
    }
    catch (Exception ex)
    {
        System.Diagnostics.Debug.WriteLine($"Error Acquiring Token Silently:{System.Environment.NewLine}{ex}");
        return;
    }

    if (authResult != null)
    {
        MG_token.Tag = authResult.AccessToken;
        MG_token.Text = "成功";
        MG_token.BackColor = Color.Green;
    }
    else
    {
        MG_token.Text = "失败";
        MG_token.BackColor = Color.Red;
    }
}

缓存改变事件

在 2 个或更多应用程序共享相同令牌缓存的情况下,可以订阅一个事件来确定应用程序仍在运行时是否添加或删除了新帐户。当单个应用程序使用令牌缓存时不需要。

复制
cacheHelper.CacheChanged += (object sender, CacheChangedEventArgs args) =>
{
    Console.WriteLine($"Cache Changed, Added: {args.AccountsAdded.Count()} Removed: {args.AccountsRemoved.Count()}");
};

感觉很棒!可以赞赏支持我哟~

0 打赏

评论 (0)

登录后评论
QQ咨询 邮件咨询 狗哥推荐