Blazor - LocalStorageService 无法在 DelegatingHandler 中工作

问题描述 投票:0回答:1

我正在使用 Blazored.LocalStorage 库来存储从 API 登录方法返回的 JWT 令牌。然后,我在每个其他 API 调用中再次使用它来检索它并将其作为不记名令牌发送。我将以前的功能性硬编码 HTTP 客户端迁移到使用 Refit 库以及 DelegatingHandler,用于将 JWT 令牌添加到每个请求的 Authorization 标头。处理程序看起来像这样:

internal sealed class AuthenticationHandler(ILocalStorageService storageService) : DelegatingHandler
{
    private readonly ILocalStorageService _storageService = storageService;

    protected async override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {
        var authToken = await _storageService.GetItemAsStringAsync("test", cancellationToken);

        if (!string.IsNullOrEmpty(authToken))
            request.Headers.Authorization = new AuthenticationHeaderValue("bearer", authToken);

        return await base.SendAsync(request, cancellationToken);
    }
}

以下是我注册 Refit 客户的方法:

builder.Services.AddRefitClient<ISomeRefitClientInterface>(refitSettings)
    .ConfigureHttpClient(options =>
    {
        options.BaseAddress = new Uri(config["APIs:MainAPI"]!);
        options.Timeout = TimeSpan.FromMinutes(5);
    })
    .AddHttpMessageHandler<AuthenticationHandler>()
    .AddHttpMessageHandler<LoggingHandler>()
    .AddHttpMessageHandler<RetryHandler>();

最后 2 个处理程序工作完美,但 AuthenticationHandler 绝对不想与本地存储有任何关系,因为它会抛出以下异常:

JavaScript interop calls cannot be issued at this time. This is because the component is being  statically rendererd. When prerendering is enabled, JavaScript interop calls can only be performed  during the OnAfterRenderAsync lifecycle method.

在我的整个应用程序中全局禁用预渲染,并且本地存储在任何组件的 OnInitializedAsync 方法中都可以正常工作(如果预渲染打开,则不会出现这种情况)。在使用 Refit 之前,我对 HTTP 客户端进行了硬编码,并且以相同的方式完成身份验证,但没有使用 DelegatingHandler。每个客户端都继承自一个公共基类,并且将令牌添加到 auth 标头的逻辑就在那里,并为每个请求手动调用。

快速谷歌搜索显示 GitHub 上报告的类似问题,但我看不到解决方案。看来使用 Javascript 互操作的库根本无法在 DelegatingHandlers 中工作,因为我尝试过 Blazored.SessionStorage 并获得了相同的结果。

有什么方法可以从 DelegatingHandler 访问本地存储吗?

asp.net-core blazor local-storage delegatinghandler javascript-interop
1个回答
0
投票

根据我的经验,即使全局禁用预渲染(SSR),有些地方仍然以某种方式使用SSR。在所有渲染模式下可以访问值的唯一方法是 cookie。
您可以在 SSR 模式下使用 httpcontext.request/response.cookie。并在Interacrive server/WASM模式下使用JSinterop操作浏览器cookie。
首先在客户端项目中安装

Microsoft.AspNetCore.Http 2.2.2

然后在“App.razor”底部添加以下脚本。

<script>
    function getCookie(key) {
        const value = `; ${document.cookie}`;
        const parts = value.split(`; ${key}=`);
        if (parts.length === 2) return parts.pop().split(';').shift();
    }

    function setCookie(key, value) {
        document.cookie = `${key}=${value}`;
    }
</script>

然后就可以通过httpcontext判断rendermode来操作cookie了。

@using Microsoft.AspNetCore.Http
...
        if (httpContext != null)   //when SSR httpContext is not null.
        {
            //get cookie
            var cookieValue = httpContext.Request.Cookies["key1"];
            //set cookie
            httpContext.Response.Cookies.Append("key1","value1");
        }
        else   // when InterActive Server/WASM , httpContext is null. So use javascript interop.
        {
            //get cookkie
            var cookieValue =await _JSruntime.InvokeAsync<string>("getCookie","key1");
            //set cookie
            await _JSruntime.InvokeVoidAsync("setCookie", "key1", "value1");
        }

© www.soinside.com 2019 - 2024. All rights reserved.