【问题标题】:How do I use ValidateAntiForgeryToken in an HTTP GET request in ASP.NET Core?如何在 ASP.NET Core 的 HTTP GET 请求中使用 ValidateAntiForgeryToken?
【发布时间】:2020-09-18 23:37:34
【问题描述】:

通常你使用ValidateAntiForgeryTokenHttpPost,像这样:

[HttpPost]
[ValidateAntiForgeryToken]
public IActionResult ...

我想使用不带HttpPostValidateAntiForgeryToken,以便可以将令牌作为URL 参数传入。我怎样才能做到这一点?如果没有HttpPost,它是否可以正常工作,如果可以,参数的名称是什么?

【问题讨论】:

  • 由于 HTTP 在大多数网络浏览器中的工作方式,防伪令牌不适用于 GET 请求。
  • HTTP 会阻止它工作吗?
  • 我想通了,看看我是怎么做到的。

标签: c# asp.net-core csrf antiforgerytoken


【解决方案1】:

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

您所要做的就是在 AJAX 调用中传递一个 "RequestVerificationToken" 标头:

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

对于 POST 调用,令牌可以通过正文中的对象(或 FormData)作为 "__RequestVerificationToken" 字段传递:

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

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

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

确保AntiforgeryOptions.HeaderNameAntiforgeryOptions.FormFieldName 未被修改,否则将上面的名称更改为各自的值。

【讨论】:

    【解决方案2】:

    这有点复杂,但可能。

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

    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 请求的表单数据中获取。

    【讨论】:

      【解决方案3】:

      您需要使用 RequestVerificationToken 在您的 ajax 请求中添加标头,如下所示,它采用隐藏字段值。如果您的页面有带有 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."}" 的错误消息

      【讨论】:

        猜你喜欢
        • 2016-08-06
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-03-25
        • 2019-12-09
        • 1970-01-01
        • 2021-09-12
        相关资源
        最近更新 更多