在ASP.Net MVC中使用@Html.AntiForgeryToken()提供CSRF令牌的替代方法
我正在使用在ASP.Net MVC中使用@Html.AntiForgeryToken()提供CSRF令牌的替代方法,asp.net,asp.net-mvc-4,angular,csrf-protection,Asp.net,Asp.net Mvc 4,Angular,Csrf Protection,我正在使用ASP.Net MVC后端开发angular 2应用程序。为此,index.cshtml包含了@Html.AntiForgeryToken(){ 让originalXsrfElement=document.querySelector('[name=\uu RequestVerificationToken]'); 让身体=反应; 如果(正文){ 让helperElem=document.createElement('div'); helperElem.innerHTML=body; 让h
ASP.Net MVC
后端开发angular 2
应用程序。为此,index.cshtml
包含了@Html.AntiForgeryToken()所以我得到一个隐藏的输入元素,它的值是Token。在我的前端,我可以抓取这个令牌并将其用于我的请求。到目前为止还不错
现在,由于用户信息用于在后端生成令牌,因此我必须在某些情况下关闭令牌。描述了该问题
现在,因为我不想在我的应用程序中重新加载整个页面,所以我必须使用变通方法。为此,我在后端创建了一个局部视图,该视图使用@Html.AntiForgeryToken()发出此输入代码>作为ActionResult
使用以下简单方法:
public ActionResult GetAntiForgery()
{
return PartialView("~/Views/Home/AntiForgery.cshtml");
}
getAntiForgery(url:string) {
return this._http.get(url)
.map((response:any) => {
let originalXsrfElement = <HTMLInputElement>document.querySelector('[name=__RequestVerificationToken]');
let body = response._body;
if(body) {
let helperElem = document.createElement('div');
helperElem.innerHTML = body;
let helperInputElem = <HTMLInputElement>helperElem.firstChild;
originalXsrfElement.value = helperInputElem.value;
}
return response;
});
}
登录/注销后,我从前端调用此函数,并替换现有反伪造输入元素的值,如下所示:
public ActionResult GetAntiForgery()
{
return PartialView("~/Views/Home/AntiForgery.cshtml");
}
getAntiForgery(url:string) {
return this._http.get(url)
.map((response:any) => {
let originalXsrfElement = <HTMLInputElement>document.querySelector('[name=__RequestVerificationToken]');
let body = response._body;
if(body) {
let helperElem = document.createElement('div');
helperElem.innerHTML = body;
let helperInputElem = <HTMLInputElement>helperElem.firstChild;
originalXsrfElement.value = helperInputElem.value;
}
return response;
});
}
getAntiForgery(url:string){
返回此。\u http.get(url)
.map((响应:任意)=>{
让originalXsrfElement=document.querySelector('[name=\uu RequestVerificationToken]');
让身体=反应;
如果(正文){
让helperElem=document.createElement('div');
helperElem.innerHTML=body;
让helperInputElem=helperElem.firstChild;
originalXsrfElement.value=helperInputElem.value;
}
返回响应;
});
}
我甚至不能告诉你我最讨厌的是什么。我不喜欢提出额外的请求(但我们不要在这里深入讨论),但对我来说更可怕的是,我必须请求一些东西,取回一个html字符串,并从中提取令牌字符串
如果我是后端人员,我会杀死前端人员(我…),因为他们甚至考虑创建额外的局部视图,创建额外的方法,并且总是在登录/注销时执行两个请求,而不是一个
有更好的办法吗?例如,我想调用一个方法,该方法只需发出一个带有适当标记的JSON
,而不是HTML片段
。更好的是,在后端现有的JsonResult
方法上,我想添加新的CSRF令牌作为属性
我不是一个后端架构师,所以我通常的做法可能有一些错误,但我的后端同事并不介意我在那里做什么,所以应该不会太遥远
非常感谢您的提示。您可以在操作中使用Antifforgery.GetToken
设置返回的JSON的某些属性:
string cookieToken, formToken;
AntiForgery.GetTokens(null, out cookieToken, out formToken);
json.RequestVerificationToken = cookieToken + ":" + formToken;
然后,将其传递回下一个AJAX请求的标题中:
$.ajax("/my/awesome/url", {
type: "post",
contentType: "application/json",
data: { ... },
dataType: "json",
headers: {
'RequestVerificationToken': requestVerificationToken
}
});
因为Cookie不再处理它,所以不能只使用标准的ValidateAntiForgeryToken
属性。您需要手动检查标题并对其进行验证。但是,您应该能够创建一个可以替代使用的自定义属性:
AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, AllowMultiple = false, Inherited = true)]
public sealed class ValidateAntiForgeryTokenFromHeaderAttribute : FilterAttribute, IAuthorizationFilter
{
public void OnAuthorization(AuthorizationContext filterContext)
{
var request = filterContext.HttpContext.Request;
string cookieToken = "";
string formToken = "";
IEnumerable<string> tokenHeaders;
if (request.Headers.TryGetValues("RequestVerificationToken", out tokenHeaders))
{
string[] tokens = tokenHeaders.First().Split(':');
if (tokens.Length == 2)
{
cookieToken = tokens[0].Trim();
formToken = tokens[1].Trim();
}
}
AntiForgery.Validate(cookieToken, formToken);
}
}
AttributeUsage(AttributeTargets.Method | AttributeTargets.Class,AllowMultiple=false,Inherited=true)]
公共密封类ValidateAntiForgeryTokenFromHeaderAttribute:FilterAttribute,IAAuthorizationFilter
{
授权时的公共无效(AuthorizationContext filterContext)
{
var request=filterContext.HttpContext.request;
字符串cookieToken=“”;
字符串formToken=“”;
IEnumerable标记头;
if(request.Headers.TryGetValues(“RequestVerificationToken”,out-tokenHeaders))
{
string[]tokens=tokenHeaders.First().Split(“:”);
if(tokens.Length==2)
{
cookieToken=tokens[0]。Trim();
formToken=tokens[1].Trim();
}
}
防伪。验证(cookieToken,formToken);
}
}
然后,只需使用[ValidateAntiForgeryTokenFromHeader]
来装饰您的操作即可
[改编自的代码看起来这个问题可能会有所帮助(基本上是将防伪放在ajax标题而不是隐藏字段中):对不起,我看不出这对解决我的问题有什么帮助。问题不同。“反CSRF和ajax”链接文章中的部分似乎正是你想要的:现在我明白你想告诉我什么,我认为我们彼此误解了。请参阅我对下面答案的评论,以澄清我的问题所在。我没有得到的是@Html.AntiForgeryToken()
call插入一个html代码段,一个以令牌作为值的输入。这是否已经设置了cookie,或者为什么您的建议不再适用于cookie?我只想获得@html.AntiForgeryToken()的值
并将此字符串值作为json响应发送,而不是发送一个视图。对于我来说,您的方法似乎有点过火,仅仅是为了这个小小的“更改”。例如“前端:服务器,给我那个令牌字符串”。“服务器:不,对不起,我只能给您一个html元素…”.等等,什么?;)通常,通过AJAX请求命中的任何东西都不支持cookies。设计良好的API将基于REST,REST是无状态的(没有会话,没有cookies)。Web API肯定不支持它。