如何在 ASP.NET Core 中的 HTTP GET 请求中使用 ValidateAntiForgeryToken?
How do I use ValidateAntiForgeryToken in an HTTP GET request in ASP.NET Core?
通常你使用 ValidateAntiForgeryToken
和 HttpPost
,像这样:
[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.HeaderName
和 AntiforgeryOptions.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."}"
通常你使用 ValidateAntiForgeryToken
和 HttpPost
,像这样:
[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.HeaderName
和 AntiforgeryOptions.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."}"