如何解决HttpClient在Blazor Webassembly应用程序中不包含带有请求的cookie
我有一个带有用户服务的Blazor Webassembly应用程序,该应用程序旨在按API来检索用户的详细信息。服务看起来像这样:
public class UserDataService : IUserDataService
{
public readonly HttpClient _HttpClient;
public UserDataService(HttpClient httpClientDI)
{
_HttpClient = httpClientDI;
}
public async Task<User> GetUserInfo()
{
try
{
return await _HttpClient.GetFromJsonAsync<User>("api/users/MyUserInfo");
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
throw;
}
}
}
API专门用于从客户端请求中读取加密的cookie。该cookie包含用户的电子邮件地址,并且由用户信息服务用来检索更详细的用户信息集。
[HttpGet("MyUserInfo")]
public User MyUserInfo()
{
var myCookie = HttpContext.Request.Cookies.FirstOrDefault(c => c.Key == "MyCookie");
var userMask = JsonConvert.DeserializeObject<AuthUserMask>(Protector.Unprotect(myCookie.Value));
var user = UserService.Find(userMask.Email).FirstOrDefault();
return user;
}
当我运行Web应用程序时,我能够验证浏览器中是否存在cookie,但是当该应用程序向API发出请求时,将不包含该cookie。实际上,该请求根本不包含来自客户端的任何cookie。
我对Blazor完全陌生,我不确定这种情况下是否存在任何约定,但是目前,我只是想让这个新的Web应用程序与我们现有的服务一起使用。有没有办法确保包含cookie?我可能做错了什么?
预先感谢您的帮助。
编辑
这是创建cookie的代码。这是验证用户身份已通过的较大方法的一部分,但这是相关的部分:
{
var userJson = JsonConvert.SerializeObject(new AuthUserMask()
{
Email = user.Email,isActive = user.IsActive
});
var protectedContents = Protector.Protect(userJson);
HttpContext.Response.Cookies.Append("MyCookie",protectedContents,new CookieOptions()
{
SameSite = SameSiteMode.None,Secure = true,Path = "/",Expires = DateTime.Now.AddMinutes(60)
});
HttpContext.Response.Redirect(returnUrl);
}
编辑2
在UserDataService中尝试了以下内容,以了解会发生什么情况:
public async Task<User> GetUserInfo()
{
try
{
_HttpClient.DefaultRequestHeaders.Add("Test","ABC123");
return await _HttpClient.GetFromJsonAsync<User>("api/users/MyUserInfo");
}
catch (Exception ex)
{
Console.WriteLine(ex.Message);
throw;
}
}
不幸的是,结果是相同的-RequestCookieCollection到达API时完全为空。
解决方法
这是我在测试的Blazor WebAssembly AspNet托管应用中所做的事情:
FetchData.razor
@page "/fetchdata"
@using BlazorApp3.Shared
@inject HttpClient Http
<h1>Weather forecast</h1>
<p>This component demonstrates fetching data from the server.</p>
@if (forecasts == null)
{
<p><em>Loading...</em></p>
}
else
{
<table class="table">
<thead>
<tr>
<th>Date</th>
<th>Temp. (C)</th>
<th>Temp. (F)</th>
<th>Summary</th>
</tr>
</thead>
<tbody>
@foreach (var forecast in forecasts)
{
<tr>
<td>@forecast.Date.ToShortDateString()</td>
<td>@forecast.TemperatureC</td>
<td>@forecast.TemperatureF</td>
<td>@forecast.Summary</td>
</tr>
}
</tbody>
</table>
}
@code {
private WeatherForecast[] forecasts;
protected override async Task OnInitializedAsync()
{
Http.DefaultRequestHeaders.Add("key","someValue");
forecasts = await Http.GetFromJsonAsync<WeatherForecast[]>("WeatherForecast");
}
}
通知Http.DefaultRequestHeaders.Add("key","someValue");
在服务器端的WeatherForecastController
上,我正在寻找密钥的请求标头,如果存在,则试图获取该值:
using BlazorApp3.Shared;
using Microsoft.AspNetCore.Mvc;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Generic;
using System.Linq;
namespace BlazorApp3.Server.Controllers
{
[ApiController]
[Route("[controller]")]
public class WeatherForecastController : ControllerBase
{
// The Web API will only accept tokens 1) for users,and 2) having the access_as_user scope for this API
private static readonly string[] scopeRequiredByApi = new string[] { "user_impersonation" };
private static readonly string[] Summaries = new[]
{
"Freezing","Bracing","Chilly","Cool","Mild","Warm","Balmy","Hot","Sweltering","Scorching"
};
private readonly ILogger<WeatherForecastController> _logger;
public WeatherForecastController(ILogger<WeatherForecastController> logger)
{
_logger = logger;
}
[HttpGet]
public IEnumerable<WeatherForecast> Get()
{
if (HttpContext.Request.Headers.ContainsKey("key"))
{
var success = HttpContext.Request.Headers.TryGetValue("key",out var headervalue);
if (success)
{
_logger.LogInformation(headervalue.ToString());
}
}
var rng = new Random();
return Enumerable.Range(1,5).Select(index => new WeatherForecast
{
Date = DateTime.Now.AddDays(index),TemperatureC = rng.Next(-20,55),Summary = Summaries[rng.Next(Summaries.Length)]
})
.ToArray();
}
}
}
我能够在http请求标头上获取该值。
如果您需要创建cookie,则必须使用JsInterop
,更多详细信息在How do I create a cookie client side using blazor。
添加这个
public class CookieHandler : DelegatingHandler
{
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request,CancellationToken cancellationToken)
{
request.SetBrowserRequestCredentials(BrowserRequestCredentials.Include);
return await base.SendAsync(request,cancellationToken);
}
}
,
基于@Mihaimyh的一些见解,我能够使用用户数据服务上的自定义委派处理程序来使其工作。这样就注册了:
builder.Services.AddHttpClient<IUserDataService,UserDataService>(client => client.BaseAddress = new Uri("https://localhost:44336/"))
.AddHttpMessageHandler<CustomDelegatingHandler>();
内部使用JSInterop
运行Javascript函数来检索cookie,然后将cookie附加到使用SendAsync()
方法的所有传出请求中:
public class CustomDelegatingHandler : DelegatingHandler
{
private IJSRuntime JSRuntime;
public CustomDelegatingHandler(IJSRuntime jSRuntime) : base()
{
JSRuntime = jSRuntime;
}
protected override async Task<HttpResponseMessage> SendAsync(HttpRequestMessage request,CancellationToken cancellationToken)
{
var cookie = await JSRuntime.InvokeAsync<string>("blazorExtensions.GetCookie",new[] { "MyCookie" });
Debug.WriteLine($"My cookie: {cookie}");
request.Headers.Add("MyCookie",$"{cookie}");
return await base.SendAsync(request,cancellationToken);
}
}
Javascript函数如下所示(从W3Schools几乎逐字记录):
window.blazorExtensions = {
GetCookie: function (cname) {
var name = cname + "=";
var decodedCookie = decodeURIComponent(document.cookie);
var ca = decodedCookie.split(';');
for (var i = 0; i < ca.length; i++) {
var c = ca[i];
while (c.charAt(0) == ' ') {
c = c.substring(1);
}
if (c.indexOf(name) == 0) {
return c.substring(name.length,c.length);
}
}
return "";
}
}
我还修改了服务端的内容,以在标题中查找cookie,而不是cookie集合。现在,代替这个...
var myCookie = HttpContext.Request.Cookies.FirstOrDefault(c => c.Key == "MyCookie");
...我已经这样做了:
HttpContext.Request.Headers.TryGetValue("MyCookie",out var myCookie);
我承认我不知道它如何与Blazor应用程序中此类事件的约定保持一致,但是对于我们的目的而言,它似乎运行得很好。再次感谢大家的帮助。
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。