【问题标题】:Blazor Standalone WASM Unable to get Access Token with MSALBlazor 独立 WASM 无法使用 MSAL 获取访问令牌
【发布时间】:2021-10-03 19:05:57
【问题描述】:

为此奋斗了2天,投入了6h左右,终于决定求助了。

我有一个带有 MSAL 身份验证的独立 Blazor WASM 应用,在登录成功并尝试获取访问令牌后,我收到错误消息:

blazor.webassembly.js:1 info: Microsoft.AspNetCore.Authorization.DefaultAuthorizationService[1]
      Authorization was successful.
blazor.webassembly.js:1 crit: Microsoft.AspNetCore.Components.WebAssembly.Rendering.WebAssemblyRenderer[100]
      Unhandled exception rendering component: An exception occurred executing JS interop: The JSON value could not be converted to System.DateTimeOffset. Path: $.token.expires | LineNumber: 0 | BytePositionInLine: 73.. See InnerException for more details.
Microsoft.JSInterop.JSException: An exception occurred executing JS interop: The JSON value could not be converted to System.DateTimeOffset. Path: $.token.expires | LineNumber: 0 | BytePositionInLine: 73.. See InnerException for more details.
 ---> System.Text.Json.JsonException: The JSON value could not be converted to System.DateTimeOffset. Path: $.token.expires | LineNumber: 0 | BytePositionInLine: 73.
 ---> System.InvalidOperationException: Cannot get the value of a token type 'Null' as a string.
   at System.Text.Json.Utf8JsonReader.TryGetDateTimeOffset(DateTimeOffset& value)
   at System.Text.Json.Utf8JsonReader.GetDateTimeOffset()

此错误仅在我登录后显示。

我的设置在 .NET 5.0 上运行,身份验证提供程序是 Azure B2C 租户,我已将重定向 URI 正确配置为“单页应用程序”,并授予“offline_access”和“openid”权限。

这是我的 Program.cs

public class Program
    {
        public static async Task Main(string[] args)
        {
            var builder = WebAssemblyHostBuilder.CreateDefault(args);
            builder.RootComponents.Add<App>("#app");

            builder.Services.AddScoped(sp => new HttpClient { BaseAddress = new Uri(builder.HostEnvironment.BaseAddress) });

            // Authenticate requests to Function API
            builder.Services.AddScoped<APIFunctionAuthorizationMessageHandler>();
            
            //builder.Services.AddHttpClient("MyAPI", 
            //    client => client.BaseAddress = new Uri("<https://my_api_uri>"))
            //  .AddHttpMessageHandler<APIFunctionAuthorizationMessageHandler>();

            builder.Services.AddMudServices();

            builder.Services.AddMsalAuthentication(options =>
            {
                // Configure your authentication provider options here.
                // For more information, see https://aka.ms/blazor-standalone-auth
                builder.Configuration.Bind("AzureAd", options.ProviderOptions.Authentication);

                options.ProviderOptions.LoginMode = "redirect";
                options.ProviderOptions.DefaultAccessTokenScopes.Add("openid");
                options.ProviderOptions.DefaultAccessTokenScopes.Add("offline_access");
            });

            await builder.Build().RunAsync();
        }
    }

我有意注释掉了指向 AuthorizationMessageHandler 的 HTTPClient 链接。 “AzureAD”配置具有设置为 true 的 Authority、ClientId 和 ValidateAuthority。

public class APIFunctionAuthorizationMessageHandler : AuthorizationMessageHandler
    {
        public APIFunctionAuthorizationMessageHandler(IAccessTokenProvider provider,
        NavigationManager navigationManager)
        : base(provider, navigationManager)
        {
            ConfigureHandler(
                authorizedUrls: new[] { "<https://my_api_uri>" });
                //scopes: new[] { "FunctionAPI.Read" });
        }
    }

我已经尝试定义诸如 openid 或自定义 API 范围之类的范围,但现在没有。没有区别。

然后为了引发异常,我所做的只是简单的:

@code {
    private string AccessTokenValue;

    protected override async Task OnInitializedAsync()
    {
        var accessTokenResult = await TokenProvider.RequestAccessToken();
        AccessTokenValue = string.Empty;

        if (accessTokenResult.TryGetToken(out var token))
        {
            AccessTokenValue = token.Value;
        }
    }
}

最终目标是使用这样的东西:

   try {
      var httpClient = ClientFactory.CreateClient("MyAPI");
      var resp = await httpClient.GetFromJsonAsync<APIResponse>("api/Function1");
      FunctionResponse = resp.Value;
      Console.WriteLine("Fetched " + FunctionResponse);
   }
   catch (AccessTokenNotAvailableException exception)
   {
      exception.Redirect();
   }

但是返回相同的错误,甚至在它运行之前看起来是这样的。 此代码也是 Blazor 组件的 OnInitializedAsync()。

欢迎任何想法或建议。 我被困住了,有点绝望。

我怀疑没有从 Azure AD B2C 请求或返回访问令牌,但假定这是 AuthorizationMessageHandler 作业。

非常感谢任何欢迎。

谢谢。

【问题讨论】:

  • 错误消息让我相信反序列化程序在尝试反序列化具有Null Expires 属性的令牌时会引发错误。您是否能够缩小发生错误的确切范围。是在 TryGetToken 还是在 await TokenProvider?
  • @DekuDesu 发生在“await TokenProvider.RequestAccessToken()”上
  • 我决定在美化后调试 JavaScript 文件 AuthenticationService.js,方法“async getTokenCore(e)”在第 171 行,并且仅从 _msalApplication.acquireTokenSilent(n) 返回 IdToken;访问令牌实际上是空的。

标签: c# .net-core azure-ad-b2c msal blazor-webassembly


【解决方案1】:

发现问题。

在 JavaScript 端进行一些调试后,文件 AuthenticationService.js,方法“async getTokenCore(e)”在第 171 行经过美化后,我已经确认实际上没有返回访问令牌,只有 IdToken。

通过阅读有关向 Azure AD B2C 请求访问令牌的文档,它提到根据您定义的范围,它将更改返回给您的内容。

范围“openid”告诉它您需要一个 IdToken,然后“offline_access”告诉它您需要一个刷新令牌,最后有一个巧妙的技巧,您可以将范围定义为 App Id,它会返回一个访问令牌. 更多细节在这里:https://docs.microsoft.com/en-us/azure/active-directory-b2c/access-tokens#openid-connect-scopes

所以我在 Program.cs、builder.Services.AddMsalAuthentication 步骤中更改了我的代码。

现在看起来像这样:

builder.Services.AddMsalAuthentication(options =>
            {
                // Configure your authentication provider options here.
                // For more information, see https://aka.ms/blazor-standalone-auth
                builder.Configuration.Bind("AzureAd", options.ProviderOptions.Authentication);

                options.ProviderOptions.LoginMode = "redirect";
                options.ProviderOptions.DefaultAccessTokenScopes.Add("00000000-0000-0000-0000-000000000000");
                //options.ProviderOptions.DefaultAccessTokenScopes.Add("openid");
                //options.ProviderOptions.DefaultAccessTokenScopes.Add("offline_access");
            });

我设置了我在此 Blazor 应用上使用的实际应用 ID,而不是“00000000-0000-0000-0000-000000000000”。

现在错误没有发生并且访问令牌返回。

谢谢。

【讨论】:

  • 感谢您的有趣帖子。我很好奇你为什么注释掉 openid 和 offline_access?您不再使用这些,还是它们会干扰接收访问令牌?
  • @user1227445 谢谢。我在答案的第三段中解释了您的要求。希望对你有帮助
猜你喜欢
  • 2021-10-22
  • 2021-06-06
  • 2021-12-02
  • 1970-01-01
  • 1970-01-01
  • 2013-08-23
  • 2020-09-07
  • 1970-01-01
  • 2021-01-22
相关资源
最近更新 更多