如何在 ASP.NET Core 中的 HTTP GET 请求中使用 ValidateAntiForgeryToken?

How do I use ValidateAntiForgeryToken in an HTTP GET request in ASP.NET Core?

通常你使用 ValidateAntiForgeryTokenHttpPost,像这样:

[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult ...

我想在没有 HttpPost 的情况下使用 ValidateAntiForgeryToken,这样我就可以将令牌作为 URL 参数传入。我怎样才能做到这一点?它会在没有 HttpPost 的情况下工作吗?如果可以,参数的名称是什么?

有点复杂,但是有可能。

首先,你需要使用依赖注入来获得一些东西:

private readonly IAntiforgery _antiforgery;
private readonly AntiforgeryOptions _options;

public YourController(IAntiforgery antiforgery, IOptions<AntiforgeryOptions> optionsAccessor)
{
    _antiforgery = antiforgery;
    _options = optionsAccessor.Value;
}

然后,您可以修改您的操作以添加此代码:

public IActionResult YourAction(string parameter1, string requestToken)
{
    // Begin antiforgery token validation
    typeof(DefaultAntiforgery).GetMethod("CheckSSLConfig", BindingFlags.NonPublic | BindingFlags.Instance)
        ?.Invoke(_antiforgery, new object[] { HttpContext }); 
    var tokens = new AntiforgeryTokenSet(requestToken, HttpContext.Request.Cookies[_options.Cookie.Name], _options.FormFieldName, _options.HeaderName);
    if (tokens.CookieToken == null)
    {
        throw new AntiforgeryValidationException("Cookie token cannot be null");
    }

    if (tokens.RequestToken == null)
    {
        throw new AntiforgeryValidationException("Request token cannot be null");
    }
    typeof(DefaultAntiforgery).GetMethod("ValidateTokens", BindingFlags.NonPublic | BindingFlags.Instance)
        ?.Invoke(_antiforgery, new object[] { HttpContext, tokens });
    // End antiforgery token validation

    return Content(parameter1);
}

这与调用 IAntiforgery.ValidateRequestAsync 时的 运行 代码基本相同,但修改为手动创建 AntiforgeryTokenSet 而不是仅调用 IAntiforgeryTokenStore.GetRequestTokensAsync。这意味着您可以从任何地方(在本例中为 URL 参数)获取请求令牌,而不仅仅是从 POST 请求的表单数据中获取。

有了 ASP.NET Core 3.1,事情似乎容易多了。

你所要做的就是在 AJAX-call 中传递一个 "RequestVerificationToken" header:

let token = $('input[name="__RequestVerificationToken"]').val();
let headers = { "RequestVerificationToken": token };
$.ajax({ ..., type: 'GET', headers: headers, ... });

对于 POST-calls,令牌可以通过 body(或 FormData)中的 object 作为 "__RequestVerificationToken" 字段传递:

let postData["__RequestVerificationToken"] = token;
$.ajax({ ..., type: 'POST', data: postData, ... });

控制器中的方法可以定义如下:

[ValidateAntiForgeryToken]
public IActionResult GetNotifications()
{
    var notifications = _notificationService.GetNotifications();
    return Json(notifications);
}

确保 AntiforgeryOptions.HeaderNameAntiforgeryOptions.FormFieldName 没有被修改,否则用相应的值更改上面的名称。

您需要使用 RequestVerificationToken 在您的 ajax 请求中添加 header,如下所示,它采用隐藏字段值。如果您的页面具有使用 post 方法的表单标记,则会自动生成此隐藏字段。

$.ajax({
    type: "GET",
    url: "api/YourCustomMethod",
    headers: {
        "RequestVerificationToken":
            $('input:hidden[name="__RequestVerificationToken"]').val()
    },                    
    contentType: "application/json; charset=utf-8",
    dataType: "json",
    success: OnSuccess,
    error: OnErrorCall
});

如果你的页面没有表单标签,那么你必须在页面上调用@Html.AntiForgeryToken(),生成RequestVerificationToken


你的方法应该是这样的

[HttpGet]
[ValidateAntiForgeryToken]
public IActionResult GetABC()
{
    // your logic
}

当您直接从浏览器 运行 api url 时可以验证这一点,您将收到这样的错误消息 "{"type":"https://tools.ietf.org/html/rfc7231#section-6.5.1","title":"Bad Request","status":400,"traceId":"|f27cc9e8-434210ecb10deb2f."}"