簡體   English   中英

您如何使用 Microsoft Identity 和 Azure AD 處理身份驗證和令牌刷新

[英]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 對我來說仍然是新的。

我想要發生的事情:

  • 用戶使用他們的 Microsoft 帳戶登錄
  • 用戶的 session 長達 12 小時不間斷(所有代幣管理都在幕后進行)
  • 12 小時后會話/cookie 將過期,用戶將需要重新登錄

怎么了:

  • 用戶登錄並通過身份驗證
  • 大約一小時后,應用程序會在用戶下次執行任何操作(例如嘗試導航到新頁面)時觸發對 /authorize 端點的調用
  • 這會導致應用程序在用戶當前所在的頁面上重新加載(從而中斷他們的體驗)

其他問題:在與上述類似的情況下,我也收到 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);

下面的代碼片段是在嘗試上面的 post 場景時發生的情況。 發布后的CORS錯誤

tl/dr 問題是,使用 Microsoft Identity 庫/MSAL,我如何:

  • 靜默刷新用戶的令牌
  • 避免重新加載頁面以獲取新令牌(即:調用 /authorize 並重定向以獲取新令牌)
  • 從客戶端處理令牌過期(避免在發布表單時出現 CORS 錯誤)。 我是否需要添加一個額外的客戶端 js 庫來管理它?

我曾嘗試搜索 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));
    });

關鍵項目是:

  • AddSessionTokenCaches() 已替換為 AddDistributedTokenCaches() 添加了對
  • AddDistributedTokenCaches 之后的 AddDistributedSqlServerCache(我還創建了支持數據庫表,有關詳細信息,請參見此處

進行這些更改后,我便能夠通過我配置的 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.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM