随着ASP.Net Core 3.0的发布,我试图在我的MVC核心应用程序中利用服务器端Blazor功能。 我首先创建了一个简单的导航组件,从中试图让用户使用指向控制器动作的按钮退出。但是,我遇到了防伪令牌验证错误,内容为:
Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker:信息:过滤器“ Microsoft.AspNetCore.Mvc.ViewFeatures.Filters.ValidateAntiforgeryTokenAuthorizationFilter”上的请求授权失败。
然后服务器返回http 400状态代码。 我正在使用Blazzor App模板代码(Visual Studio 2019中的Blazor版本0.7.0):
<AuthorizeView>
<Authorized>
<a href="/Account/Manage">Hello, @context.User.Identity.Name!</a>
<form method="post" action="/Account/Logout">
<button type="submit">Sign out</button>
</form>
</Authorized>
<NotAuthorized>
<a href="/Account/Register">Register</a>
<a href="/Account/Login">Log in</a>
</NotAuthorized>
</AuthorizeView>
我的MVC“帐户”控制器具有以 [ValidateAntiForgeryToken] 注释的注销操作,如下所示:
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Logout()
{
await _signInManager.SignOutAsync();
_logger.LogInformation("User logged out.");
return RedirectToAction(nameof(HomeController.Index), "Home");
}
过去,我将以一种形式添加@ Html.AntiForgeryToken()以符合我带注释的Logout操作。在较新版本的ASP.Net Core中,您不再需要手动添加它,因为它已包含在表单标签帮助器中。但是,这两种方法似乎都无法翻译或在Blazor组件中可用。
您如何从Blazor组件调用此MVC动作,并提供防伪令牌进行控制器验证? 还是根本不需要这种验证?
即使我的登出案例不是很大的威胁,调用其他类似注解的操作也是一样。
我可能会缺少适用于MVC和Blazor混合场景的CSRF技术概念。
答案 0 :(得分:1)
不确定为什么会弹出此异常。虽然这对我有用。 只需将其添加到_Host.cshtml文件的末尾即可。
@Html.AntiForgeryToken()
</body>
答案 1 :(得分:1)
我一直在尝试使防伪功能适用于注销 POST。我想我只是设法让它工作。我愿意接受改进建议!
我使用了关于“Blazor 服务器附加安全方案”(https://docs.microsoft.com/en-us/aspnet/core/blazor/security/server/additional-scenarios?view=aspnetcore-5.0) 的 MS 文档,该文档解释了存储 OIDC 访问和刷新令牌以在 Blazor 组件中使用的方法。我修改了该示例,以便以类似的方式使用防伪令牌,如下所示:
public class TokenProvider
{
public string AntiforgeryToken { get; set; }
}
public void ConfigureServices(IServiceCollection services)
{
...
services.AddScoped<TokenProvider>();
...
}
@page "/"
@namespace My.Pages
@inject Microsoft.AspNetCore.Antiforgery.IAntiforgery antiforgery
@addTagHelper *, Microsoft.AspNetCore.Mvc.TagHelpers
@{
var token = antiforgery.GetAndStoreTokens(HttpContext).RequestToken;
}
...
<body>
<component type="typeof(App)" render-mode="ServerPrerendered" param-AntiforgeryToken="token" />
...
@inject TokenProvider tokenProvider
<Router ....
</Router>
@code {
[Parameter]
public string AntiforgeryToken { get; set; }
protected override Task OnInitializedAsync()
{
tokenProvider.AntiforgeryToken = AntiforgeryToken;
return base.OnInitializedAsync();
}
}
@inject TokenProvider tokenProvider
...
<form method="post" action="Logout">
<input name="__RequestVerificationToken" type="hidden" value="@tokenProvider.AntiforgeryToken">
<button type="submit" class="nav-link btn btn-link" title="Log out">
<span class="oi oi-account-logout"></span>
</button>
</form>
...