使用个人用户帐户在 Blazor 服务器端应用程序上访问 MS Graph 数据的正确方法
Correct way to access MS Graph data on blazor server-side app with Individual User Acconts
我在 Blazor(ASP.NET 核心)服务器端构建了一个 Web 应用程序。该应用程序是多租户的,我需要控制谁有访问权限,因此我使用存储在 SQL 数据库中的自己的用户数据库 (DefaultIdentity)。
现在我需要访问 Microsoft Graph(对于某些用户)。我通过使用应用程序级访问来实现这一点,但我想避免让本地 IT 管理员在他们的 Azure AD 中设置它——我想遵守“最小特权原则”。
所以我希望能够添加一个登录 page/functionality 特定用户(在他们使用我的本地用户数据库登录后)可以给我的应用授权+同意检索 Calendar.Read 通过 Microsoft Graph 获得许可。
我应该怎么做?
我认为我学到的是
- 我应该使用 OAuth2.0 授权码流程
- 我的应用程序是机密应用程序(我有一个安全的服务器端)- 但这会阻止我使用 AquireTokenInteractive!?那么我应该使用 IPublicClientApplication 吗?
我能找到的所有示例都使用 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);
});
这一切似乎都奏效了。有什么想法吗?
我在 Blazor(ASP.NET 核心)服务器端构建了一个 Web 应用程序。该应用程序是多租户的,我需要控制谁有访问权限,因此我使用存储在 SQL 数据库中的自己的用户数据库 (DefaultIdentity)。
现在我需要访问 Microsoft Graph(对于某些用户)。我通过使用应用程序级访问来实现这一点,但我想避免让本地 IT 管理员在他们的 Azure AD 中设置它——我想遵守“最小特权原则”。
所以我希望能够添加一个登录 page/functionality 特定用户(在他们使用我的本地用户数据库登录后)可以给我的应用授权+同意检索 Calendar.Read 通过 Microsoft Graph 获得许可。
我应该怎么做?
我认为我学到的是
- 我应该使用 OAuth2.0 授权码流程
- 我的应用程序是机密应用程序(我有一个安全的服务器端)- 但这会阻止我使用 AquireTokenInteractive!?那么我应该使用 IPublicClientApplication 吗?
我能找到的所有示例都使用 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);
});
这一切似乎都奏效了。有什么想法吗?