首页 > 解决方案 > 使用 Blazor Asp.net Core 3.1.0 Preview 3 添加 Jwt HttpClient 处理程序

问题描述

我最近将我的项目从最新版本升级Asp.Net Core 3.0到了最新版本Asp.Net Core 3.1.0 preview 3

JwtTokenHeaderHandler我的项目正在客户端中运行 Blazor,并且我还截获管道以将 Jwt 添加到使用 my which extends发送回服务器的每个请求的标头中DelegatingHandler

我将其添加到startup.cs我的blazor.client项目中,如下所示;

        services.AddSingleton<HttpClient>(s =>
        {
            // Creating the URI helper needs to wait until the JS Runtime is initialized, so defer it.
            var uriHelper = s.GetRequiredService<NavigationManager>();
            var myHandler = s.GetRequiredService<JwtTokenHeaderHandler>();
            myHandler.InnerHandler = new WebAssemblyHttpMessageHandler();
            return new HttpClient(myHandler)
            {
                BaseAddress = new Uri(uriHelper.BaseUri)
            };
        }); 

但是,自从升级以来似乎WebAssemblyHttpMessageHandler()不再可用?

我找不到任何有关如何解决此方法的文档。

谁能建议我如何纠正这个问题?

根据 Aqua 的回答进行更新

将以下代码添加到我的Startup.cs;

        services.AddTransient(p =>
         {
             var wasmHttpMessageHandlerType = Assembly.Load("WebAssembly.Net.Http")
                 .GetType("WebAssembly.Net.Http.HttpClient.WasmHttpMessageHandler");
             var constructor = wasmHttpMessageHandlerType.GetConstructor(Array.Empty<Type>());
             return constructor.Invoke(Array.Empty<object>()) as HttpMessageHandler;
         })
         .AddTransient<JwtTokenHeaderHandler>();

从我的文件中调用AuthorizedGet 端点;.razor

var response = await Http.GetAsync<ContactTypeOutputModel[]>("ContactTypes/all");

(上面只是使用扩展方法的类型化包装服务响应);

    public static async Task<ServiceResponse<T>> GetAsync<T>(
        this HttpClient httpClient, string url)
    {
        var response = await httpClient.GetAsync(url);

        return await BuildResponse<T>(response);
    }

我仍然在服务上收到 401?并且没有输出日志表明正在使用该服务?

public class JwtTokenHeaderHandler : DelegatingHandler
{
    private readonly IAppLocalStorageService _localStorage;     
    private readonly ILogger<JwtTokenHeaderHandler> _logger;

    private readonly HttpMessageHandler _innerHandler;
    private readonly MethodInfo _method;

    public JwtTokenHeaderHandler(IAppLocalStorageService localStorage, HttpMessageHandler innerHandler, ILogger<JwtTokenHeaderHandler> logger)
    {
        _localStorage = localStorage;   
        _logger = logger;

        _innerHandler = innerHandler;
        var type = innerHandler.GetType();
        _method = type.GetMethod("SendAsync", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.InvokeMethod) ?? throw new InvalidOperationException("Cannot get SendAsync method");
        WebAssemblyHttpMessageHandlerOptions.DefaultCredentials = FetchCredentialsOption.Include;
    }

    protected override async Task<HttpResponseMessage> SendAsync(
        HttpRequestMessage request,
        CancellationToken cancellationToken)
    {
        _logger.LogDebug("Adding Jwt to Header from JwtTokenHeaderHandler: SendAsync");
        _logger.LogDebug($"Does header contain 'bearer' token: {!request.Headers.Contains("bearer")}");

        if (!request.Headers.Contains("bearer"))
        {

            _logger.LogDebug("Adding Bearer Token to Header");

            var savedToken = await _localStorage.GetTokenAsync();

            _logger.LogDebug($"Saved Token is : {savedToken}");

            if (!string.IsNullOrWhiteSpace(savedToken))
            {
                request.Headers.Authorization = new AuthenticationHeaderValue("bearer", savedToken);
            }
        }

        //return await base.SendAsync(request, cancellationToken);
        return await (_method.Invoke(_innerHandler, new object[] { request, cancellationToken }) as Task<HttpResponseMessage>);
    }
}

任何想法为什么这没有被击中?

标签: asp.net-coreblazorblazor-client-side

解决方案


WebAssemblyHttpMessageHandler已被 Mono 取代,WasmHttpMessageHandler因为您无法向WebAssembly.Net.Http添加依赖项。为了为 blazor WASM 创建一个 DependencyHandler,我做了一些小技巧:

    public class OidcDelegationHandler : DelegatingHandler
    {
        private readonly IUserStore _userStore;
        private readonly HttpMessageHandler _innerHanler;
        private readonly MethodInfo _method;

        public OidcDelegationHandler(IUserStore userStore, HttpMessageHandler innerHanler)
        {
            _userStore = userStore ?? throw new ArgumentNullException(nameof(userStore));
            _innerHanler = innerHanler ?? throw new ArgumentNullException(nameof(innerHanler));
            var type = innerHanler.GetType();
            _method = type.GetMethod("SendAsync", BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.InvokeMethod) ?? throw new InvalidOperationException("Cannot get SendAsync method");
            WebAssemblyHttpMessageHandlerOptions.DefaultCredentials = FetchCredentialsOption.Include;
        }
        protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
        {
            request.Headers.Authorization = new AuthenticationHeaderValue(_userStore.AuthenticationScheme, _userStore.AccessToken);            
            return _method.Invoke(_innerHanler, new object[] { request, cancellationToken }) as Task<HttpResponseMessage>;
        }
    }

是否在 DI 中设置:

return services
    .AddTransient(p =>
    {
        var wasmHttpMessageHandlerType =  Assembly.Load("WebAssembly.Net.Http")
            .GetType("WebAssembly.Net.Http.HttpClient.WasmHttpMessageHandler");
        var constructor = wasmHttpMessageHandlerType.GetConstructor(Array.Empty<Type>());
        return constructor.Invoke(Array.Empty<object>()) as HttpMessageHandler;
    })

完整代码在这里


推荐阅读