2009-08-28 18 views
17

Tôi đang trong quá trình thêm chức năng giao diện người dùng vào trang web WebForms/MVC lai. Trong trường hợp này, tôi đang thêm một số tính năng UI AJAX vào một trang WebForms (thông qua jQuery), và dữ liệu đến từ một MVC JsonResult. Mọi thứ đang hoạt động 100%, với một ngoại lệ:Sử dụng MVC HtmlHelper từ WebForm

Tôi muốn triển khai tính năng bảo vệ XSRF của AntiForgeryToken. Tôi đã sử dụng nó kết hợp với các thuộc tính ValidateAntiForgeryToken trên ứng dụng MVC tinh khiết của tôi, nhưng muốn biết làm thế nào để thực hiện các Html.AntiForgeryToken() phương pháp trong WebForms. Here's an example using a UrlHelper.

Tôi gặp một số sự cố khi xem ViewContext/RequestContext "được giả lập" đúng cách. Tôi nên sử dụng HtmlHelpers như thế nào trong một trang WebForms?

Chỉnh sửa: Tôi đang tìm cách truy xuất AntiForgeryToken từ trang WebForms của tôi, không phải từ MVC JsonResult.

+0

Tôi có cùng một vấn đề - một trang WebForms kế thừa cần đăng lên một hành động MVC với một 'AntiForgeryToken'. Tôi muốn thêm 'Html.AntiForgeryToken()' vào trang WebForms mà không cần viết lại nó trong MVC. – Keith

Trả lời

6

Phương pháp quan trọng là trong mã nguồn MVC: GetAntiForgeryTokenAndSetCookie

Điều này tạo ra một thể hiện của một lớp kín nội bộ gọi AntiForgeryData.

Ví dụ được tuần tự hóa thành một cookie "__RequestVerificationToken_" + phiên bản mã hóa cơ sở 64 của đường dẫn ứng dụng.

Ví dụ tương tự của AntiForgeryData được đăng theo thứ tự thành đầu vào bị ẩn.

Phần độc đáo của AntiForgeryData đang có với một RNGCryptoServiceProvider.GetBytes()

Tất cả điều này có thể bị giả mạo trong một trang WebForms, bit lộn xộn chỉ là serialization của lớp kín ẩn. Thật không may là phương pháp quan trọng (GetAntiForgeryTokenAndSetCookie) dựa trên ViewContext.HttpContext.Request để lấy cookie, trong khi WebForm cần sử dụng HttpContext.Current.Request thay thế.


Cập nhật

Không có nhiều thử nghiệm và rất nhiều mã, nhưng tôi nghĩ rằng tôi đã nứt này với một sự phản ánh ít. Nơi mà tôi đã sử dụng phản ánh tôi đã rời khỏi dòng tương đương nhận xét ở trên:

using System; 
using System.Reflection; 
using System.Web; 
using System.Web.Mvc; 

/// <summary>Utility to provide MVC anti forgery tokens in WebForms pages</summary> 
public class WebFormAntiForgery 
{ 
    /// <summary>Create an anti forgery token in a WebForms page</summary> 
    /// <returns>The HTML input and sets the cookie</returns> 
    public static string AntiForgeryToken() 
    { 
     string formValue = GetAntiForgeryTokenAndSetCookie(); 

     // string fieldName = AntiForgeryData.GetAntiForgeryTokenName(null); 
     var mvcAssembly = typeof(HtmlHelper).Assembly; 
     var afdType = mvcAssembly.GetType("System.Web.Mvc.AntiForgeryData"); 
     string fieldName = Convert.ToString(afdType.InvokeMember(
      "GetAntiForgeryTokenName", 
      BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.InvokeMethod, 
      null, 
      null, 
      new object[] { null })); 

     TagBuilder builder = new TagBuilder("input"); 
     builder.Attributes["type"] = "hidden"; 
     builder.Attributes["name"] = fieldName; 
     builder.Attributes["value"] = formValue; 
     return builder.ToString(TagRenderMode.SelfClosing); 
    } 

    static string GetAntiForgeryTokenAndSetCookie() 
    { 
     var mvcAssembly = typeof(HtmlHelper).Assembly; 
     var afdType = mvcAssembly.GetType("System.Web.Mvc.AntiForgeryData"); 

     // new AntiForgeryDataSerializer(); 
     var serializerType = mvcAssembly.GetType("System.Web.Mvc.AntiForgeryDataSerializer"); 
     var serializerCtor = serializerType.GetConstructor(new Type[0]); 
     object serializer = serializerCtor.Invoke(new object[0]); 

     // string cookieName = AntiForgeryData.GetAntiForgeryTokenName(HttpContext.Current.Request.ApplicationPath); 
     string cookieName = Convert.ToString(afdType.InvokeMember(
      "GetAntiForgeryTokenName", 
      BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.InvokeMethod, 
      null, 
      null, 
      new object[] { HttpContext.Current.Request.ApplicationPath })); 

     // AntiForgeryData cookieToken; 
     object cookieToken; 
     HttpCookie cookie = HttpContext.Current.Request.Cookies[cookieName]; 
     if (cookie != null) 
     { 
      // cookieToken = Serializer.Deserialize(cookie.Value); 
      cookieToken = serializerType.InvokeMember("Deserialize", BindingFlags.InvokeMethod, null, serializer, new object[] { cookie.Value }); 
     } 
     else 
     { 
      // cookieToken = AntiForgeryData.NewToken(); 
      cookieToken = afdType.InvokeMember(
       "NewToken", 
       BindingFlags.Public | BindingFlags.Static | BindingFlags.InvokeMethod, 
       null, 
       null, 
       new object[0]); 

      // string cookieValue = Serializer.Serialize(cookieToken); 
      string cookieValue = Convert.ToString(serializerType.InvokeMember("Serialize", BindingFlags.InvokeMethod, null, serializer, new object[] { cookieToken })); 

      var newCookie = new HttpCookie(cookieName, cookieValue) { HttpOnly = true }; 

      HttpContext.Current.Response.Cookies.Set(newCookie); 
     } 

     // AntiForgeryData formToken = new AntiForgeryData(cookieToken) 
     // { 
     //  CreationDate = DateTime.Now, 
     //  Salt = salt 
     // }; 
     var ctor = afdType.GetConstructor(new Type[] { afdType }); 
     object formToken = ctor.Invoke(new object[] { cookieToken }); 

     afdType.InvokeMember("CreationDate", BindingFlags.SetProperty, null, formToken, new object[] { DateTime.Now }); 
     afdType.InvokeMember("Salt", BindingFlags.SetProperty, null, formToken, new object[] { null }); 

     // string formValue = Serializer.Serialize(formToken); 
     string formValue = Convert.ToString(serializerType.InvokeMember("Serialize", BindingFlags.InvokeMethod, null, serializer, new object[] { formToken })); 
     return formValue; 
    } 
} 

Việc sử dụng sau đó tương tự như MVC:

WebFormAntiForgery.AntiForgeryToken() 

Nó tạo ra cùng một cookie và HTML tương tự như MVC phương pháp.

Tôi đã không làm phiền với các phương pháp miền và muối, nhưng chúng sẽ khá dễ dàng để thêm vào.

+0

Xin chào, tôi chỉ cố gắng thực hiện điều này trong một biểu mẫu web ứng dụng (.NET 4.0, MVC 3.0) và có lỗi "Tham chiếu đối tượng không được đặt thành một đối tượng" từ dòng này: var serializerCtor = serializerType.GetConstructor (kiểu mới [0]); Ai đó có thể trợ giúp? Tôi là một chút ra khỏi chiều sâu của tôi ở đây. – cjacques

+0

@BFOT này được viết trên ASP.Net 2, MVC 1 và là một tổng số hack - Tôi phản ánh ra công cụ mã thông báo chống giả mạo của họ, nhưng đó là tất cả các phương pháp riêng tư. Cơ hội là điều này sẽ cần một chút cập nhật với mỗi phiên bản mới của ASP và MVC, tải về nguồn MVC 3 và xem các phương thức đã thay đổi như thế nào - nếu chúng ta rất may mắn, họ thậm chí có thể đã tiếp xúc chúng để WebForms có thể sử dụng chúng. – Keith

+0

cảm ơn câu trả lời. Tôi sẽ có một cái nhìn tại nguồn MVC mới nhất vào cuối tuần này để xem tôi có thể làm việc được không. Xin vui lòng gửi một phiên bản sửa đổi của mã trên của bạn nếu có một số thời gian miễn phí. ;) – cjacques

0

bạn có thể tạo một HtmlHelper mới trong điều khiển của bạn và sau đó kéo chống xrsf từ đó:

var htmlHelper = new HtmlHelper(
    new ViewContext(
     ControllerContext, 
     new WebFormView("omg"), 
     new ViewDataDictionary(), 
     new TempDataDictionary()), 
     new ViewPage()); 

var xsrf = htmlHeler.AntiForgeryToken; 

myObject.XsrfToken = xsrf; 

return JsonResult(myObject); 
+0

Đó là sự hiểu biết của tôi rằng AntiForgeryToken thiết lập một cookie, và tiêm một trường biểu mẫu ẩn, vì vậy cả hai có thể được so sánh. Làm thế nào để thực hiện điều đó? –

1

Theo mặc định, ASP.NET WebForms đã bao gồm các biện pháp để xác nhận sự kiện và ViewState. Phil Haack nói một chút về điều đó trong bài đăng được liên kết. chiến lược giảm nhẹ XSRF đang nói về here (Scott Hanselman)here (Dino Esposito)

+1

Các liên kết rất tốt, cảm ơn. Tôi đã hy vọng cho một cách để sử dụng AntiForgeryToken cụ thể, bởi vì "người tiêu dùng" của dịch vụ web MVC là trên một trang WebForms (mà tôi sẽ không được viết lại trong MVC.) –

17

Tôi biết đây là một câu hỏi cũ, nhưng tôi đã gặp phải vấn đề này ngày hôm nay và nghĩ rằng tôi muốn chia sẻ. Tôi đang làm việc trong MVC4 và có một điều khiển webform (.ascx) được chia sẻ giữa cả hai MVC (thông qua RenderPartial) và WebForms. Trong điều khiển đó, tôi cần một mã thông báo chống đông. May mắn thay, có một helper bây giờ bạn có thể sử dụng trong webforms của bạn bây giờ đó là đơn giản như này:

<%= AntiForgery.GetHtml() %> 

Điều này sẽ làm cho dấu hiệu chống giả mạo của bạn như bạn sẽ nhận được trong MVC.

Here's the MS link to it.

+0

Tuyệt vời, đây là cách tốt hơn để giải quyết vấn đề trong WebForms 2/MVC 3 trở lên. – Keith

Các vấn đề liên quan