在 NET46 上使用 ASP.NET5 Web API 而没有 System.Web.Helpers 的防伪令牌

AntiForgery Token using ASP.NET5 Web API without System.Web.Helpers on NET46

尝试在 ASP.NET5 (又名 vNext) API

上实施防伪

我找到的所有文章都来自this article并使用System.Web.Helpers.AntiForgery.GetTokens这不应该是ASP.NET5[的方式

private static string GetTokenHeaderValue() 
{
   string cookieToken, formToken;
   System.Web.Helpers.AntiForgery.GetTokens(null, out cookieToken, out formToken);
   return cookieToken + ":" + formToken;
}

是否有任何实现实际显示如何在 ASP.NET5

中检索这些令牌

额外来源ASP.NET5 AntiForgery Source Code

在控制器生成

using Microsoft.AspNet.Mvc;
using Microsoft.Framework.DependencyInjection;

namespace MyApp.App.Controllers
{
    public class MyController : Controller
    {
        public string GetAntiForgeryTokens()
        {
            var antiForgery = Context.RequestServices.GetService<AntiForgery>();
            AntiForgeryTokenSet antiForgeryTokenSet = antiForgery.GetTokens(Context, null);
            string output = antiForgeryTokenSet.CookieToken + ":" + antiForgeryTokenSet.FormToken;
            return output;
        }
    }    
}

在查看时生成

@inject AntiForgery antiForgery
@functions
{
    public string GetAntiForgeryTokens()
    {
        AntiForgeryTokenSet antiForgeryTokenSet = antiForgery.GetTokens(Context, null);
        string output = antiForgeryTokenSet.CookieToken + ":" + antiForgeryTokenSet.FormToken;
        return output;
    }
}

<body>
    @GetAntiXsrfToken()
</body>

验证

var antiForgery = Context.RequestServices.GetService<AntiForgery>();
antiForgery.Validate(Context, new AntiForgeryTokenSet(formToken, cookieToken));

使用 MVC 实现此目的的另一种方法是使用 HTML 帮助程序在创建 cookie 和隐藏输入字段令牌的视图上获取令牌。

<form>
@Html.AntiForgeryToken()
</form>

HTML 输出:

<input name="__RequestVerificationToken" type="hidden" value="*** />

现在表单令牌已经存在,我们可以在 header 中发送令牌或将其添加到 API 期望的模型中。 API 可以使用处理自定义防伪令牌验证的 ActionFilter 进行保护。类似于 [Authorize] 的工作方式

[ValidateAntiForgeryToken]
public class MyController : ApiController

逻辑是读取 headers,其中可以找到 cookie 和 header 值标记。然后可以使用对

的调用对其进行评估
AntiForgery.Validate(cookieToken, headerToken);

然后过滤器可以接受或拒绝请求。

拒绝返回:

HttpStatusCode.Forbidden

现在有 sample in the source code。该示例使用 Angular 1.x。在该示例的基础上,通过使用 Filter 进行验证,这是一个粗略的示例。在 Startup 需要设置令牌:

public void Configure(IApplicationBuilder app, IAntiforgery antiforgery)
{
    app.Use(next => context =>
    {
        if (!context.Request.Path.Value.StartsWith("/api/"))
        {
            // We can send the request token as a JavaScript-readable cookie, and Angular will use it by default.
            var tokens = antiforgery.GetAndStoreTokens(context);
            context.Response.Cookies.Append("XSRF-TOKEN", tokens.RequestToken, new CookieOptions() { HttpOnly = false });
        }

        return next(context);
    });
    …
}

然后可以使用过滤器来验证令牌:

public class AntiforgeryValidationFilter : IAsyncActionFilter
{
    private readonly IAntiforgery antiforgery;

    public AntiforgeryValidationFilter(IAntiforgery antiforgery)
    {
        this.antiforgery = antiforgery;
    }

    public async Task OnActionExecutionAsync(ActionExecutingContext context, ActionExecutionDelegate next)
    {
        if (context.HttpContext.Request.Path.Value.StartsWith("/api/"))
        {
            await antiforgery.ValidateRequestAsync(context.HttpContext);
        }
        await next();
    }
}

然后在Startup中注册过滤器:

public void ConfigureServices(IServiceCollection services)
{
    // Angular's default header name for sending the XSRF token.
    services.AddAntiforgery(options => options.HeaderName = "X-XSRF-TOKEN");

    services
        .AddMvc(options =>
            options.Filters.Add(typeof(AntiforgeryValidationFilter)))
        …
}