使用个人用户帐户在blazor服务器端应用程序上访问MS Graph数据的正确方法

使用个人用户帐户在blazor服务器端应用程序上访问MS Graph数据的正确方法,blazor,msal,Blazor,Msal,我在Blazor(ASP.NET核心)服务器端构建了一个web应用程序。应用程序是多租户的,我需要控制谁有访问权,因此我使用存储在SQL数据库中的自己的用户数据库(DefaultIdentity) 现在我需要访问Microsoft Graph(对于某些用户)。我通过使用应用程序级访问来实现这一点,但我希望避免让本地IT管理员在他们的Azure广告中设置这一点,我希望遵守“最低特权原则” 因此,我希望能够添加一个登录页面/功能,在该页面/功能中,特定用户(在使用我的本地用户数据库登录后)可以向我的

我在Blazor(ASP.NET核心)服务器端构建了一个web应用程序。应用程序是多租户的,我需要控制谁有访问权,因此我使用存储在SQL数据库中的自己的用户数据库(DefaultIdentity)

现在我需要访问Microsoft Graph(对于某些用户)。我通过使用应用程序级访问来实现这一点,但我希望避免让本地IT管理员在他们的Azure广告中设置这一点,我希望遵守“最低特权原则”

因此,我希望能够添加一个登录页面/功能,在该页面/功能中,特定用户(在使用我的本地用户数据库登录后)可以向我的应用程序自动化+同意检索日历。通过Microsoft Graph读取权限

我该怎么做

我想我学到的是

  • 我应该使用OAuth2.0授权代码流
  • 我的应用程序是一个机密应用程序(我有一个安全的服务器端)-但这阻止我使用AquireTokenInteractive!?那么我应该使用IPublicClient应用程序吗

我能找到的所有示例都使用Azure AD登录用户。是否有一个“手动”实现授权代码流的示例,我可以看一下?

我现在有了一个可行的解决方案,但我想听听你们中的一些人是否有任何意见-我没有看到的任何警告或陷阱

我的解决方案如下:

我正在使用“标准流”获取PublicClientApplication

        IPublicClientApplication app = PublicClientApplicationBuilder
            .Create(publicAppClientId)
            .WithRedirectUri("http://localhost")                
            .Build();
        
        TokenCacheHelper.EnableSerialization(app.UserTokenCache);
        
        var accounts = await app.GetAccountsAsync();
        IAccount firstAccount = accounts.FirstOrDefault();
                              
        AuthenticationResult authResult = null;
        try
        {
            authResult = await app.AcquireTokenSilent(scopesList, firstAccount)
                        .ExecuteAsync();                
        }
        catch (MsalUiRequiredException)
        {                
            try
            {
                authResult = await app.AcquireTokenInteractive(scopesList)
                    .ExecuteAsync();                 
            }
            catch (MsalException msalex)
            {
                System.Diagnostics.Debug.WriteLine($"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)
        {
            System.Diagnostics.Debug.WriteLine($"Access token:{System.Environment.NewLine}{authResult.AccessToken}");                
                           
            // Use the token
            InteractiveAuthenticationProvider authProvider = new InteractiveAuthenticationProvider(app, scopesList);
            GraphServiceClient = new GraphServiceClient(authProvider);                
        }
    }
我已经使用TokenCacheHelper添加了一个分布式SQL缓存

 public class TokenCacheHelper
 {
    private IDistributedCache _cache;
    private string lookUpAccount = string.Empty;
    private byte[] token = null;

    public TokenCacheHelper(IDistributedCache cache, string user)
    {
        _cache = cache;
        lookUpAccount = user;
    }

    public void EnableSerialization(ITokenCache tokenCache)
    {
        tokenCache.SetBeforeAccess(BeforeAccessNotification);
        tokenCache.SetAfterAccess(AfterAccessNotification);
    }
    
    private void BeforeAccessNotification(TokenCacheNotificationArgs args)
    {
        if (token == null)
        {
            token = _cache.Get(lookUpAccount);
        }
        args.TokenCache.DeserializeMsalV3(token);
    }

    private void AfterAccessNotification(TokenCacheNotificationArgs args)
    {
        if (args.HasStateChanged)
        {
            token = args.TokenCache.SerializeMsalV3();
            _cache.Set(lookUpAccount, token);
        }
    }
}
在startup.cs中添加DistributedSqlServerCache,标记上有“无限”超时

services.AddDistributedSqlServerCache(options =>
        {
            options.ConnectionString = Configuration.GetConnectionString("TestDbContext");
            options.SchemaName = "dbo";
            options.TableName = "TestCache";
            options.DefaultSlidingExpiration = TimeSpan.FromDays(300);
            options.ExpiredItemsDeletionInterval = TimeSpan.FromDays(300);
        });

所有这些似乎都在起作用。有什么想法吗?

我正在使用类似的客户机/服务器系统。问题:如何获取传递给
AcquireTokenSilent
firstAccount
?通过这个var accounts=wait app.GetAccountsAsync();IAccount firstAccount=accounts.FirstOrDefault();非常感谢。尝试过-GetAccountsAsync()为我提供了一个空列表:(-但是,当我使用“AcquireTokenInteractive()时),然后我在rutime的UI中得到一个列表。我想知道如何以编程方式访问此列表?它也为我这样做,直到我实现了TokenCaching,然后它为我提供了我的帐户。也就是说,在我运行了第一个AcquireTokenInteractive并将我的令牌保存在TokenCache中之后。我使用了一个SQL TokenCache,具有非常高的性能长期到期,到目前为止,MSAL已经能够自动更新令牌,使用只需登录/确认一次。