如何通过 HttpContext 访问 Blazor Server .Net 6 中的 Cookie?

How do I access cookies in Blazor Server .Net 6 via HttpContext?

提问人:user4779 提问时间:1/17/2023 更新时间:6/12/2023 访问量:1399

问:

遗憾的是,有关在 Blazor Server 中访问 Cookie 的教程和先前的 StackOverflow 答案似乎在新的 .Net 版本中失效。例如,我无法获得以下任何一个答案(从它们在 .net 6 中没有的注释来看): 如何在服务器端 Blazor 中使用 HttpContext 对象检索有关用户、用户代理的信息 如何在服务器端 Blazor 中访问 HttpContext?

我有一个包含以下代码的 Program.cs 文件:

..
builder.Services.AddHttpContextAccessor();
..  

它还有一个应用程序。MapPost 方法,用于设置 cookie:HttpContext.Response.Cookies.Append

我可以确认cookie有效,因为在postman中,我可以在查询此应用程序时成功检索它。MapPost 方法。

尝试在 Login.Razor 页面中查询该方法时,它可以正常工作,但未设置 cookie。在此 Login.razor 中,httpContextAccessor.HttpContext.Request.Cookies[“my_cookie”] 始终返回 null(即使响应本身是 200 OK,并且我可以很好地读取其内容,没有可通过 HttpContext 检索的 cookie)。

这似乎是一个常见的问题,从两个链接的答案来看,这个问题已经解决,但现在在 .net 6 中似乎又坏了。如何在 Blazor Server .net 6 中访问 HttpContext 以访问查询中发送的 Cookie?

.NET Blazor

评论


答:

5赞 Arani 1/17/2023 #1

请不要在 Blazor Server 中使用。AddHttpContextAccessor()

我在 中使用以下方法。净6:

我首先修改_Host.cshtml文件,如下所示。

@{
var myCookie = HttpContext.Request.Cookies["CookieName"];
}
<component type="typeof(App)" render-mode="ServerPrerendered" param-AccessToken="myCookie" />

我将 Cookie 信息放入 myCookie 变量中,并将其分配给组件的 .param-AccessToken

然后,我转到文件并将变量定义为级联值。如下:App.razorAccessToken

<CascadingValue Name="AccessToken" Value="AccessToken">
<CascadingAuthenticationState>
    <Router AppAssembly="@typeof(Program).Assembly">
        <Found Context="routeData">
            <AuthorizeRouteView RouteData="@routeData" DefaultLayout="@typeof(MainLayout)" />
        </Found>
        <NotFound>
            <LayoutView Layout="@typeof(MainLayout)">
                <p>Sorry, there's nothing at this address.</p>
            </LayoutView>
        </NotFound>
    </Router>
</CascadingAuthenticationState>
 @code{
    [Parameter]
     public string AccessToken { get; set; }
 }

最后,任何需要 Cookie 信息值的组件只需要将其定义为级联参数即可。例如,我创建了一个名为的组件,并将其代码如下:ShowToken.razor

@page "/showtoken"

<p>This is a part of Cookie info @(AccessToken != null ? AccessToken.Substring(0,30) : "(null)")</p>


@code {
    [CascadingParameter(Name = "AccessToken")] public string AccessToken { get; set; }
}

评论

0赞 user4779 1/18/2023
谢谢,由于某种原因,这似乎仍然不起作用。Program.cs中的App.MapPost保持不变,对吗?它仍然会在 postman 中生成一个 cookie。在剃刀文件中,我仍在使用“await Http.PostAsync(..)”调用同一终结点生成响应,该响应有效,但仍未设置 cookie。除了调用 Http.PostAsync 之外,我是否应该在 .razor 文件中设置 cookie?同样在 App.razor 中只是为了确认,我将已经存在的代码替换为您的代码(默认的 <Router AppAssembly..>,还包括 </CascadingValue>?
0赞 Arani 1/18/2023
在 BlazorServer 中,只有 httpcontext 在应用启动时具有正确的值。因此,无论你想对 Cookie 执行什么操作,你都只能在开始时执行(类似于 _host.cshtml),之后 httpcontext 将不再包含保证的正确值。在开发环境中,你可能会从 httpcontext 中获取一个值,但在实际环境中发布项目后,不能保证该值是正确的。无法在 .razor 文件中设置 cookie 值,因为你无权访问有保证的 httpcontext。
0赞 Arani 1/18/2023
您可以使用任何您想要的 App.razor,但是,您必须将其放在 App.razor 的顶部。对不起,我已经放了,但它没有显示。但它可以在后期编辑模式下看到。<CascadingValue Name="AccessToken" Value="AccessToken"></CascadingValue>
0赞 Arani 1/18/2023
您能确切地告诉我您需要从 cookie 中获得哪些信息吗?是否与用户信息有关?
1赞 Arani 1/18/2023
是的,也不是。可以在运行时在 Blazor Server 中设置 cookie,但是,只需在应用启动时,就可以在运行时使用 for 组件和 for 类获取 cookie。CascadingValueAuthenticationStateProvider
0赞 John Rah 6/12/2023 #2

在 .net6 及更高版本中,可以使用 Blazor 状态管理

  1. 使用 localStorage 保持选项卡和浏览器实例之间的状态。
  2. 使用 sessionStorage 仅在选项卡/浏览器打开时保持状态。

localStorage 将是 AccessToken 的最佳选择。

在您想要访问存储的任何位置注入。组件/页面可以使用。

[Inject] ProtectedLocalStorage localStorage {get; set;}

@using Microsoft.AspNetCore.Components.Server.ProtectedBrowserStorage
@inject ProtectedLocalStorage localStorage

保存 AccessToken,如下所示:

await localStorage.SetAsync("AccessToken", "123");

要检索该值,请执行以下操作:

ProtectedBrowserStorageResult<string> storedResult = await localStorage.GetAsync<string>("AccessToken");
if (storedResult.Success)
{
   string AccessToken = storedResult.Value.ToString();
}

警告:由于这在后台使用 Javascript,因此如果在组件渲染之前使用它,则会出现预渲染错误。两种选择:

在 _Host.cshtml 中,将呈现模式从“ServerPrerendered”更改为“Server”

        <component type="typeof(App)" render-mode="Server" />
        <component type="typeof(HeadOutlet)" render-mode="Server" />

或者,通过 OnAfterRenderAsync 检索值

 protected override async Task OnAfterRenderAsync(bool firstRender)
    {
        if (firstRender)
        {
            ProtectedBrowserStorageResult<string> storedResult = await localStorage.GetAsync<string>("AccessToken");
            if (storedResult.Success)
            {
                string AccessToken = storedResult.Value.ToString();
            }
            
        }
        await base.OnAfterRenderAsync(firstRender);
    }