2014-04-01 26 views
5

我有了與AntiForgeryToken形式到底在哪把antiforgeryToken

using (Html.BeginForm(action, "Account", new { ReturnUrl = returnUrl }, FormMethod.Post, new { Id = "xcrf-form" })) 

這生成一個隱藏字段

<input name="__RequestVerificationToken" type="hidden" value="p43bTJU6xjctQ-ETI7T0e_0lJX4UsbTz_IUjQjWddsu29Nx_UE5rcdOONiDhFcdjan88ngBe5_ZQbHTBieB2vVXgNJGNmfQpOm5ATPbifYE1"> 

在我的角度視圖(即裝在一個div佈局頁面在佈局網頁,我這樣做

<form class="form" role="form" ng-submit="postReview()"> 

而且我對postReview(代碼)如下

$scope.postReview = function() { 
    var token = $('[name=__RequestVerificationToken]').val(); 

    var config = { 
     headers: { 
      "Content-Type": "multipart/form-data", 
      // the following when uncommented does not work either 
      //'RequestVerificationToken' : token 
      //"X-XSRF-TOKEN" : token 
     } 
    } 

    // tried the following, since my other MVC controllers (non-angular) send the token as part of form data, this did not work though 
    $scope.reviewModel.__RequestVerificationToken = token; 

    // the following was mentioned in some link I found, this does not work either 
    $http.defaults.headers.common['__RequestVerificationToken'] = token; 

    $http.post('/Review/Create', $scope.reviewModel, config) 
    .then(function (result) { 
     // Success 
     alert(result.data); 
    }, function (error) { 
     // Failure 
     alert("Failed"); 
    }); 
} 

我的MVC創建方法如下

[HttpPost] 
    [ValidateAntiForgeryToken] 
    [AllowAnonymous] 
    public ActionResult Create([Bind(Include = "Id,CommentText,Vote")] ReviewModel reviewModel) 
    { 
     if (User.Identity.IsAuthenticated == false) 
     { 
      // I am doing this instead of [Authorize] because I dont want 302, which browser handles and I cant do client re-direction 
      return new HttpStatusCodeResult(HttpStatusCode.Forbidden); 
     } 

     // just for experimenting I have not yet added it to db, and simply returning 
     return new JsonResult {Data = reviewModel, JsonRequestBehavior = JsonRequestBehavior.AllowGet}; 
    } 

所以無論身在何處,我把道理,不管我用「的Content-Type」(我試過應用JSON和WWW-窗體-urlencoded)我總是得到錯誤「所要求的防僞表單字段" __RequestVerificationToken "不存在。」

我甚至嘗試命名__RequestVerificationToken和RequestVerificationToken

爲什麼我的服務器沒有找到該死的令牌?

我還查看了一些鏈接,要求您實現自己的AntiForgeryToeknVerifyAttrbute並驗證以cookieToken形式發送的令牌:formToken,我沒有嘗試過,但爲什麼我無法讓它工作,而這適用於MVC控制器(非角柱)

回答

5

是的。默認情況下,MVC框架將檢查Request.Form["__RequestVerificationToken"]

檢查MVC source code

public AntiForgeryToken GetFormToken(HttpContextBase httpContext) 
    { 
     string value = httpContext.Request.Form[_config.FormFieldName]; 
     if (String.IsNullOrEmpty(value)) 
     { 
      // did not exist 
      return null; 
     } 

     return _serializer.Deserialize(value); 
    } 

您需要創建自己的過濾器,以Request.Header

Code Snippet from Phil Haack's Article檢查 - MVC 3

private class JsonAntiForgeryHttpContextWrapper : HttpContextWrapper { 
    readonly HttpRequestBase _request; 
    public JsonAntiForgeryHttpContextWrapper(HttpContext httpContext) 
    : base(httpContext) { 
    _request = new JsonAntiForgeryHttpRequestWrapper(httpContext.Request); 
    } 

    public override HttpRequestBase Request { 
    get { 
     return _request; 
    } 
    } 
} 

private class JsonAntiForgeryHttpRequestWrapper : HttpRequestWrapper { 
    readonly NameValueCollection _form; 

    public JsonAntiForgeryHttpRequestWrapper(HttpRequest request) 
    : base(request) { 
    _form = new NameValueCollection(request.Form); 
    if (request.Headers["__RequestVerificationToken"] != null) { 
     _form["__RequestVerificationToken"] 
     = request.Headers["__RequestVerificationToken"]; 
    } 
} 

    public override NameValueCollection Form { 
    get { 
     return _form; 
    } 
    } 
} 

[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, 
    AllowMultiple = false, Inherited = true)] 
public class ValidateJsonAntiForgeryTokenAttribute : 
    FilterAttribute, IAuthorizationFilter { 
    public void OnAuthorization(AuthorizationContext filterContext) { 
    if (filterContext == null) { 
     throw new ArgumentNullException("filterContext"); 
    } 

    var httpContext = new JsonAntiForgeryHttpContextWrapper(HttpContext.Current); 
    AntiForgery.Validate(httpContext, Salt ?? string.Empty); 
    } 

    public string Salt { 
    get; 
    set; 
    } 

    // The private context classes go here 
} 

退房這裏MVC 4 implementation,以避免salt問題

[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class, 
       AllowMultiple = false, Inherited = true)] 
public sealed class ValidateJsonAntiForgeryTokenAttribute 
          : FilterAttribute, IAuthorizationFilter 
{ 
    public void OnAuthorization(AuthorizationContext filterContext) 
    { 
     if (filterContext == null) 
     { 
      throw new ArgumentNullException("filterContext"); 
     } 

     var httpContext = filterContext.HttpContext; 
     var cookie = httpContext.Request.Cookies[AntiForgeryConfig.CookieName]; 
     AntiForgery.Validate(cookie != null ? cookie.Value : null, 
          httpContext.Request.Headers["__RequestVerificationToken"]); 
    } 
} 
+0

感謝您的回答,根據你說什麼,我決定把令牌形式本身要做到這一點,我需要按照http://stackoverflow.com/a/14868725/2475810 – indichimp

0

正如穆拉利建議我想我需要把窗體本身的toekn,所以我試圖把令牌作爲表單數據的一部分,我需要在https://stackoverflow.com/a/14868725/2475810

解釋編碼表單數據這種方法在服務器端不需要額外的代碼,我們也不需要創建和加入cookie和表單令牌。只需通過對數據進行表單編碼並將令牌包含爲上述答案中解釋的字段之一,我們就可以實現它。

1

我有同樣的問題。原來,我不需要在我的角度js代碼中明確設置防僞標記。 MVC控制器預計這個令牌值將從1.表單域2. cookie中傳遞。過濾器等同,並且當它們匹配時是高興的。 當我們提交表單時,反僞造令牌的隱藏字段會自動提供其值。Cookie由瀏覽器自動設置。正如我所說,我們不需要明確地做任何事情。

問題確實是請求的內容類型。默認情況下,它應用程序/ json,因此a.f.令牌值(或者更確切地說是任何表單數據)未被接收。 繼爲我工作:

// create the controller 
var RegisterController = function ($scope, $http) { 

    $scope.onSubmit = function (e) { 
     // suppress default form submission 
     e.preventDefault(); 
     var form = $("#registerform"); 

     if (form.valid()) { 
      var url = form.attr('action'); 
      var data = form.serialize(); 

      var config = { 
       headers: { 
        'Content-type':'application/x-www-form-urlencoded', 
       } 
      }; 

      $http.post(url, data, config).success(function (data) { 
       alert(data); 
      }).error(function(reason) { 
       alert(reason); 
      }); 

     } 
    }; 
}; 
0

您應該對這樣的HTTP請求:

$http({ 
    url: '/Review/Create', 
    data: "__RequestVerificationToken=" + token + "&param1=1&param2=2", 
    method: 'POST', 
    headers: { 
     'X-Requested-With': 'XMLHttpRequest', 
     'Accept': 'application/json, text/javascript, */*; q=0.01', 
     'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8' 
    } 
    }).success(function(result) { 
    alert(result.data); 
    }).error(function(error) { 
    alert("Failed"); 
    }); 
+0

中的解釋對錶單進行編碼。請求數據在此代碼中發送到哪裏?我只看到令牌被單獨發送。 – ProfK

+0

您必須在標記後的數據屬性中附加您的參數。防爆。 「__RequestVerificationToken =」+ token +「&param1 = 10&param2 = 20」 –

+0

我知道,我只是使用總新手的聲音來建議你可能會在代碼中顯示。 – ProfK