在 Blazor 服务器端创建和读取 cookie 的最简单方法是什么。
似乎所有的解决方案都是针对 Blazor Web 组件的,每当我使用这些解决方案时,Response.Cookies.Append("") 和 Request.Cookies[] 选项都不起作用。
在
wwwroot/index.html
(Blazor WebAssembly) 或 Pages/_Host.cshtml
(Blazor Server) 内,编写以下 javascript 代码:
<script>
window.WriteCookie = {
WriteCookie: function (name, value, days) {
var expires;
if (days) {
var date = new Date();
date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
expires = "; expires=" + date.toGMTString();
}
else {
expires = "";
}
document.cookie = name + "=" + value + expires + "; path=/";
}
}
window.ReadCookie = {
ReadCookie: 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 "";
}
}
</script>
然后,将以下示例代码写入 Razor 组件(.razor):
@inject IJSRuntime JsRuntime;
<button class="btn" @onclick="WriteCookies">
Write Cookie
</button>
<button class="btn" @onclick="ReadCookies">
Read Cookie
</button>
<p>The cookie is @myCookieValue</p>
@code {
public string myCookieValue { get; set; } = "";
protected async Task WriteCookies()
{
await JsRuntime.InvokeAsync<object>("WriteCookie.WriteCookie", "cookieName", "cookieValue", DateTime.Now.AddMinutes(1));
}
protected async Task ReadCookies()
{
myCookieValue= await JsRuntime.InvokeAsync<string>("ReadCookie.ReadCookie", "cookieName");
}
}
如果您想从 Blazor 组件访问 Cookie,您需要注入 IHttpContextAccessor 如下所示
[Inject]
IHttpContextAccessor HttpContextAccessor { get; set; }
然后您可以使用注入的 HttpContextAccessor 从 Request 对象访问 Cookies
var token = httpContextAccessor.HttpContext.Request.Cookies["access_token"];
要设置访问令牌,请使用:
CookieOptions options = new CookieOptions();
options.Expires = DateTime.Now.AddDays(1);
httpContextAccessor.HttpContext.Response.Cookies.Append("access_token", response.access_token, options);
如果您想从服务访问 Cookie,那么您需要在服务的构造函数中使用依赖注入添加 IHttpContextAccessor,如下所示:
public AccessoryService(HttpClient httpClient,
IHttpContextAccessor HttpContextAccessor)
{
this.httpClient = httpClient;
httpContextAccessor = HttpContextAccessor;
}
请在启动时添加 services.AddHttpContextAccessor(); 以进行依赖注入。
最后你可以使用从 Request 对象检索到的令牌来调用 api:
public async Task<IEnumerable<AccessoryDto>> GetAccessories()
{
var token = httpContextAccessor.HttpContext.Request.Cookies["access_token"];
httpClient.DefaultRequestHeaders.Authorization = new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer",token);
var accessories = await httpClient.GetFromJsonAsync<AccessoryDto[]>("api/accessory");
return accessories;
}
我找到了使用本地存储解决 Blazor 服务器端 Cookie 问题的绝佳解决方案。
首先,使用以下命令获取 NuGet Blazored LocalStorage:
Install-Package Blazored.LocalStorage
我必须更新我的 System.Text.Json,请从 https://www.nuget.org/packages/System.Text.Json/
执行此操作将以下内容添加到 Startup.cs 中:
public void ConfigureServices(IServiceCollection services)
{
services.AddBlazoredLocalStorage(); // local storage
services.AddBlazoredLocalStorage(config =>
config.JsonSerializerOptions.WriteIndented = true); // local storage
}
或者在最新的.NET版本中
using Blazored.LocalSorage;
var builder = WebApplication.CreateBuilder(args);
// add after builder initialization:
builder.Services.AddBlazoredLocalStorage(); // local storage
builder.Services.AddBlazoredLocalStorage(config => config.JsonSerializerOptions.WriteIndented = true); // local storage
在您的 Razor 页面上(我使用 Index.razor 进行测试):
@page "/"
@inject Blazored.LocalStorage.ILocalStorageService localStorage
<button @onclick="HandleSubmit">Create Cookie</button> @* Create your cookie *@
@code{
public async Task HandleSubmit()
{
await localStorage.SetItemAsync("cookieName", "Jason Bourne");
}
protected override async Task OnAfterRenderAsync(bool firstRender)
{
var cookieContent = await localStorage.GetItemAsync<string>("cookieName");
if (cookieContent == null)
{
Console.WriteLine("Cookie is blank");
}
else
{
Console.WriteLine("We have a cookie with contents: " + cookieContent);
}
}
}
无意冒犯其他人,但这些答案可能比您需要的更复杂。
您可以使用 JavaScript Interop 在客户端执行任何您想要的操作。 这样,您就可以直接控制一切,而不是依赖库或插件。
使用上述所有示例。我想出了这个
Javascript
const Empty = '';
window.Cookie = {
Read: function () {
return (document.cookie == Empty) ? '[name]=[value]' : decodeURIComponent(document.cookie);
},
Write: function (name, value, days) {
document.cookie = name + '=' + value + this.ExpireOn(days) + ';path=/';
},
ExpireOn: function (days) {
return Number.isFinite(days) ? ';expires=' + new Date().AddDay(days).toGMTString() : Empty;
}
}
Date.prototype.AddDay = function(days) {
this.setDate(this.getDate() + days);
return this;
}
添加cookie.cs
namespace Blazor;
public class Cookie
{
private IDictionary<string, string> _values;
private readonly IJSRuntime _js;
public Cookie(IJSRuntime js) => _js = js;
public async Task<string> Get(string name) => (await Read()).TryGetValue(name, out var val) ? val : string.Empty;
public async Task Set(string name, string val, int? days = null)
{
await Write(name, val, days);
(await Read()).UpSert(name, val);
}
private async Task<IDictionary<string, string>> Read() =>
_values ??= (await _js.InvokeAsync<string>(COOKIE.READ))
.Split(STR.SEMICOLON)
.Select(nv => nv.Split(STR.EQUAL))
.ToDictionary(nv => nv.First().Trim(), nv => nv.Last().Trim());
private async Task Write(string name, string val, int? days) => await _js.InvokeAsync<string>(COOKIE.WRITE, name, val, days);
}
添加范围
services.AddScoped<Cookie>();
将 Cookie 注入组件并在 OnAfterRenderAsync 中使用它。示例
protected async override Task OnAfterRenderAsync(bool firstRender)
{
if (!firstRender)
return;
var val = await Cookie.Get(COOKIE.LANG.NAME);
_selectedValue = string.IsNullOrEmpty(val) ? Cache.DefaultLang : val;
_mudSelect?.SelectedValuesChanged.InvokeAsync();
}
此方法可与本地存储或会话存储一起使用。您只需要编写最少的 JavaScript 即可在客户端读取/写入它,并在服务器端编写一个包装器。 Cookie.cs 可以注入任何组件并用作用户数据会话存储。
IHttpContext Accessor 不是 Blazor 方式。任何客户端都应该可以通过 IJSRuntime 访问。
在我看来,在 Blazor 服务器端中读取 cookie 的最简单方法是 HttpContextAccessor,但写入 的最简单方法是 Javascript:
@inject IHttpContextAccessor httpContext
@inject IJSRuntime jsRuntime
var myCookie= httpContext.HttpContext
.Request.Cookies.FirstOrDefault(c=>c.Name=="myCookieName");
jsRuntime.InvokeVoidAsync(
$"document.cookie=\"{myCookieName}={myStringifiedValue}; max-age={180}; path=/;\"");