[英]How do you handle authentication and token refresh with Microsoft Identity and Azure AD
我正在嘗試針對 Azure AD 保護 .Net 6.0 / Razor 頁 web 應用程序。 我能夠使用 Azure AD 完成應用程序注冊並成功驗證用戶身份。 我面臨的問題發生在頒發的令牌過期時。 我有一些使用 Angular 和 IdentityServer 實現的經驗,但 Razor Page/Microsoft Identity 對我來說仍然是新的。
我想要發生的事情:
怎么了:
其他問題:在與上述類似的情況下,我也收到 CORS 錯誤。 此處的不同之處在於,當(假定的)令牌過期發生時,當用戶處於表單數據輸入的中間時,就會發生這種情況。 當他們單擊提交以發布表單時,將觸發 302 xhr / 重定向到 /authorize 端點。 此調用會導致 CORS 錯誤。 需要刷新頁面才能觸發成功調用(並且他們需要重新開始他們的表單)。 更新:這是由於 AJAX 調用而發生的(與表單/帖子無關)。 請參閱最后的編輯。
理想情況下,我希望令牌在即將到期時通過刷新令牌自動(並且靜默地)刷新。 當然,我也想避免 CORS 錯誤的情況,當他們在令牌過期時嘗試發布。
一些代碼片段(注意:我手動向現有應用程序添加身份驗證,我沒有使用任何腳手架/模板來創建初始項目)。
注意:我最初在沒有定義自定義 authOptions 的情況下嘗試了以下實現,但是在調試和不同的解決嘗試期間,它存在於下面的 state 中。兩種方式的結果都是一致的。
程序.cs
var builder = WebApplication.CreateBuilder(args);
var config = builder.Configuration;
var services = builder.Services;
services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApp(
authOptions =>
{
config.Bind("AzureAD", authOptions);
authOptions.MaxAge = TimeSpan.FromHours(12);
authOptions.SaveTokens = true;
},
sessionOptions =>
{
sessionOptions.Cookie.MaxAge = TimeSpan.FromHours(12);
sessionOptions.Cookie.Name = "Custom-Cookie-Name";
sessionOptions.ExpireTimeSpan = TimeSpan.FromHours(12);
sessionOptions.SlidingExpiration = false;
})
.EnableTokenAcquisitionToCallDownstreamApi(config.GetValue<string>("GraphApi:Scopes")?.Split(' '))
.AddMicrosoftGraph(config.GetSection("GraphApi"))
.AddSessionTokenCaches();
services.AddRazorPages(options =>
{
options.Conventions.AddPageRoute("/Disclaimer", "/");
})
.AddMvcOptions(options =>
{
var policy = new AuthorizationPolicyBuilder().RequireAuthenticatedUser().Build();
options.Filters.Add(new AuthorizeFilter(policy));
});
services.AddHttpContextAccessor();
........
var app = builder.Build();
if (!app.Environment.IsDevelopment())
{
app.UseExceptionHandler("/Error");
app.UseHsts();
}
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseSession();
app.UseAuthentication();
app.UseAuthorization();
app.UseEndpoints(endpoints =>
{
endpoints.MapControllers();
endpoints.MapRazorPages();
});
app.UseSaveUserDetailsOnAuthentication();
app.UseIdentityPageInitialization();
app.MapRazorPages();
app.MapControllers();
app.Run();
我還有一些中間件使用圖形服務來訪問 /me 端點並在特定條件下存儲一些用戶詳細信息(以防萬一):
圖中間件
public async Task InvokeAsync(HttpContext context, UserManager<ApplicationUser> userManager, GraphServiceClient graphServiceClient)
{
var page = context.GetRouteValue("page")?.ToString();
if (!page.IsNullOrEmpty() && page.Equals("/Disclaimer") && context.User.Identity?.IsAuthenticated == true)
{
var user = await graphServiceClient.Me
.Request()
.GetAsync()
.ConfigureAwait(false);
tl/dr 問題是,使用 Microsoft Identity 庫/MSAL,我如何:
我曾嘗試搜索 Microsoft 的文檔,但我發現沒有任何內容對此進行詳細說明。 我找到的最接近的是 MSAL 的文檔,其中提到它為您處理令牌刷新(但在我的案例中似乎沒有發生)。
我期待令牌將由底層 MSAL 庫靜默刷新,但這似乎沒有發生。 此外,我希望在前端避免與令牌過期相關的 CORS 錯誤。
編輯:雖然我的主要問題仍然存在,但我相信我找到了次要問題的解決方案:CORS 問題實際上是通過AJAX調用 API 觸發的。 本文概述了 Microsoft.Identity.Web v1.2.0+ 現在處理這種情況。 我現在對如何處理它有一個模糊的想法,但仍然需要嘗試實現。
經過進一步研究,問題的根源似乎與我對“AddSessionTokenCaches”的使用有關。 雖然我不明白為什么會發生這種情況的內部工作原理,但似乎我的用戶的授權會話/cookie 在使用這種方法約 60 分鍾后變得無效。
我還在此處找到了一個參考資料,解釋了這些 session 令牌緩存具有范圍內的生命周期,當 TokenAcquisition 用作 singleton 時不應使用,我相信使用 Microsoft Graph API(“AddMicrosoftGraph”)就是這種情況。
解決方案我將 session 令牌緩存切換為分布式 SQL 令牌緩存。
將我原來帖子中的代碼替換為以下內容:
var builder = WebApplication.CreateBuilder(args);
var config = builder.Configuration;
var services = builder.Services;
string connectionString = builder.Configuration.GetConnectionString("_ConnectionString_");
services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApp(
identityOptions =>
{
config.Bind("AzureAD", identityOptions);
identityOptions.MaxAge = TimeSpan.FromHours(12);
},
cookieAuthOptions =>
{
cookieAuthOptions.Cookie.MaxAge = TimeSpan.FromHours(12);
cookieAuthOptions.Cookie.Name = "Custom-Cookie-Name";
cookieAuthOptions.ExpireTimeSpan = TimeSpan.FromHours(12);
cookieAuthOptions.SlidingExpiration = false;
})
.EnableTokenAcquisitionToCallDownstreamApi(config.GetValue<string>("GraphApi:Scopes")?.Split(' '))
.AddMicrosoftGraph(config.GetSection("GraphApi"))
.AddDistributedTokenCaches();
services.AddDistributedSqlServerCache(options =>
{
options.ConnectionString = connectionString;
options.SchemaName = "dbo";
options.TableName = "T_TOKEN_CACHE";
options.DefaultSlidingExpiration = TimeSpan.FromMinutes(90);
});
services.AddRazorPages(options =>
{
options.Conventions.AddPageRoute("/Disclaimer", "/");
})
.AddMvcOptions(options =>
{
var policy = new AuthorizationPolicyBuilder().RequireAuthenticatedUser().Build();
options.Filters.Add(new AuthorizeFilter(policy));
});
關鍵項目是:
進行這些更改后,我便能夠通過我配置的 cookie 身份驗證選項(參見上面的“cookieAuthOptions”)正確控制我的用戶身份驗證 session。 我能夠將“cookieAuthOptions.ExpireTimeSpan”設置為一分鍾並驗證它是否成功強制驗證(重定向)。 我還能夠將其設置為 12 小時,並驗證用戶的 session 在最初的 60 分鍾到期后 window 似乎保持完好。我將繼續對此進行測試並在出現其他問題時提供更新。 我現在可以繼續管理此會話/cookie(根據不活動情況延長/過期)。
目前,我只使用 Azure AD 頒發的令牌在初始登錄時訪問 Microsoft Graph 的 /me 端點(如果用戶的基本信息已更改,則更新我們系統中的用戶基本信息)。 否則,我不使用/不需要令牌。 我假設 Microsoft Identity Web / MSAL 庫將處理令牌刷新,如果我要添加可以在令牌過期后調用的任何其他調用,但到目前為止尚未確認。
如果有人對原始問題有進一步的解釋,或建議使用 Microsoft Identity Web 更好地實施此問題,請告訴我。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.