2010-09-28 28 views
5

Tôi đang cố gắng sử dụng nhà cung cấp tùy chỉnh ITempDataProvider để lưu trữ TempData trong cookie của trình duyệt thay vì trạng thái phiên. Tuy nhiên, mọi thứ hoạt động tốt ngoại trừ việc tôi không thể xóa cookie khỏi luồng Trả lời sau khi đọc.ASP.NET MVC TempData trong cookie trình duyệt

Bất kỳ ý tưởng nào?
Cảm ơn!

public class CookieTempDataProvider : ITempDataProvider 
    { 
     internal const string TempDataCookieKey = "__ControllerTempData"; 
     HttpContextBase _httpContext; 

     public CookieTempDataProvider(HttpContextBase httpContext) 
     { 
      if (httpContext == null) 
      { 
       throw new ArgumentNullException("httpContext"); 
      } 
      _httpContext = httpContext; 
     } 

     public HttpContextBase HttpContext 
     { 
      get 
      { 
       return _httpContext; 
      } 
     } 

     protected virtual IDictionary<string, object> LoadTempData(ControllerContext controllerContext) 
     { 
      HttpCookie cookie = _httpContext.Request.Cookies[TempDataCookieKey]; 
      if (cookie != null && !string.IsNullOrEmpty(cookie.Value)) 
      { 
       IDictionary<string, object> deserializedTempData = DeserializeTempData(cookie.Value); 

       // Remove cookie     
       cookie.Expires = DateTime.MinValue; 
       cookie.Value = string.Empty; 
       _httpContext.Request.Cookies.Remove(TempDataCookieKey); 

       if (_httpContext.Response != null && _httpContext.Response.Cookies != null) 
       { 
        HttpCookie responseCookie = _httpContext.Response.Cookies[TempDataCookieKey]; 
        if (responseCookie != null) 
        { 
         // Remove cookie 
         cookie.Expires = DateTime.MinValue; 
         cookie.Value = string.Empty; 
         _httpContext.Response.Cookies.Remove(TempDataCookieKey); 

        } 
       } 

       return deserializedTempData; 
      } 

      return new Dictionary<string, object>(); 
     } 

     protected virtual void SaveTempData(ControllerContext controllerContext, IDictionary<string, object> values) 
     { 

      string cookieValue = SerializeToBase64EncodedString(values); 
      var cookie = new HttpCookie(TempDataCookieKey); 
      cookie.HttpOnly = true; 
      cookie.Value = cookieValue; 

      _httpContext.Response.Cookies.Add(cookie); 
     } 

     public static IDictionary<string, object> DeserializeTempData(string base64EncodedSerializedTempData) 
     { 
      byte[] bytes = Convert.FromBase64String(base64EncodedSerializedTempData); 
      var memStream = new MemoryStream(bytes); 
      var binFormatter = new BinaryFormatter(); 
      return binFormatter.Deserialize(memStream, null) as IDictionary<string, object> /*TempDataDictionary : This returns NULL*/; 
     } 

     public static string SerializeToBase64EncodedString(IDictionary<string, object> values) 
     { 
      MemoryStream memStream = new MemoryStream(); 
      memStream.Seek(0, SeekOrigin.Begin); 
      var binFormatter = new BinaryFormatter(); 
      binFormatter.Serialize(memStream, values); 
      memStream.Seek(0, SeekOrigin.Begin); 
      byte[] bytes = memStream.ToArray(); 
      return Convert.ToBase64String(bytes); 
     } 

     IDictionary<string, object> ITempDataProvider.LoadTempData(ControllerContext controllerContext) 
     { 
      return LoadTempData(controllerContext); 
     } 

     void ITempDataProvider.SaveTempData(ControllerContext controllerContext, IDictionary<string, object> values) 
     { 
      SaveTempData(controllerContext, values); 
     } 
    } 
+2

Hãy thực sự cẩn thận những gì bạn lưu trữ trong cookie của khách hàng. Nói chung đó là một ý tưởng tồi để giữ nội dung ở đó. Không cố gắng phán xét, nhưng nó đang làm những thứ như vậy khiến cho [DotNetNuke đau khổ] (http://www.youtube.com/watch?v=yghiC_U2RaM) từ [khai thác lỗ hổng] gần đây (http: // weblogs.asp.net/scottgu/archive/2010/09/18/important-asp-net-security-vulnerability.aspx). –

+0

Đồng ý với @cottsak. Ngoài ra, nó được gửi cùng với * mọi yêu cầu. * Mọi hình ảnh. Mỗi tập lệnh. Mỗi ... –

+0

@cottsak và @Craig: Tôi đang cố gắng chỉ lưu trữ các thông báo hiển thị như "tin nhắn của bạn đã được gửi". Tôi không lưu trữ bất kỳ dữ liệu nhạy cảm nào trong đó. –

Trả lời

3

Xin chào, tôi cũng gặp vấn đề tương tự và vấn đề với việc triển khai CookieTempDataProvider.

Vì vậy, tôi đã sửa đổi mã một chút và giờ nó hoạt động hoàn hảo.

Khi đọc dữ liệu từ cookie, nó sẽ xóa dữ liệu khỏi cả yêu cầu và phản hồi. Nhưng thêm một cookie khác với một giá trị rỗng trong hàm SaveData được gọi khi xử lý yêu cầu hoàn tất.

Điểm cần lưu ý: Nếu bạn muốn xóa cookie, bạn phải đặt giá trị thời gian chờ và gửi lại cho khách hàng và sau đó trình duyệt sẽ xóa nó. Chúng tôi không thể làm điều đó bằng cách khác từ mã mà cookie được xử lý bởi trình duyệt

Và tôi phát hiện ra rằng việc đặt hết hạn cho DateTime.MinValue không hết hạn cookie trong chrome (không biết về các trình duyệt khác) vì vậy tôi đặt nó vào 2001/01/01 :)

Dưới đây là đoạn code làm việc

public class CookieTempDataProvider : ITempDataProvider 
{ 
    internal const string TempDataCookieKey = "__ControllerTempData"; 
    HttpContextBase _httpContext; 

    public CookieTempDataProvider(HttpContextBase httpContext) 
    { 
     if (httpContext == null) 
     { 
      throw new ArgumentNullException("httpContext"); 
     } 
     _httpContext = httpContext; 
    } 

    public HttpContextBase HttpContext 
    { 
     get 
     { 
      return _httpContext; 
     } 
    } 

    protected virtual IDictionary<string, object> LoadTempData(ControllerContext controllerContext) 
    { 
     if (_httpContext.Request.Cookies.AllKeys.Contains(TempDataCookieKey)) //we need this because 
     //Cookies[TempDataCookieKey] will create the cookie if it does not exist 
     { 
      HttpCookie cookie = _httpContext.Request.Cookies[TempDataCookieKey]; 
      if (cookie != null && !string.IsNullOrEmpty(cookie.Value)) 
      { 
       IDictionary<string, object> deserializedTempData = DeserializeTempData(cookie.Value); 

       // Remove cookie     
       cookie.Expires = new DateTime(2000, 1, 1); 
       cookie.Value = string.Empty; 
       _httpContext.Request.Cookies.Remove(TempDataCookieKey); 

       if (_httpContext.Response != null && _httpContext.Response.Cookies != null) 
       { 
        HttpCookie responseCookie = _httpContext.Response.Cookies[TempDataCookieKey]; 
        if (responseCookie != null) 
        { 
         // Remove cookie 
         cookie.Expires = new DateTime(2000, 1, 1); 
         cookie.Value = string.Empty; 
         _httpContext.Response.Cookies.Remove(TempDataCookieKey); 

        } 
       } 

       return deserializedTempData; 
      } 
     } 
     return new Dictionary<string, object>(); 
    } 

    protected virtual void SaveTempData(ControllerContext controllerContext, IDictionary<string, object> values) 
    { 
     if (values != null && values.Count > 0) 
     { 
      //there are values to set, so add the cookie. But no need to expire it as we need the browser to send the 
      //cookie back with the next request 
      string cookieValue = SerializeToBase64EncodedString(values); 
      var cookie = new HttpCookie(TempDataCookieKey); 
      cookie.HttpOnly = true; 
      cookie.Value = cookieValue; 

      _httpContext.Response.Cookies.Add(cookie); 
     } 
     else 
     { 
      //Still we need to add the cookie with the expiration set, to make the client browser remove the cookie from the request. 
      //Otherwise the browser will continue to send the cookie with the response 

      //Also we need to do this only if the requet had a tempdata cookie 

      if (_httpContext.Request.Cookies.AllKeys.Contains(TempDataCookieKey)) 
      { 
       { 
        HttpCookie cookie = _httpContext.Request.Cookies[TempDataCookieKey]; 

        // Remove the request cookie     
        cookie.Expires = new DateTime(2000, 1, 1); 
        cookie.Value = string.Empty; 
        _httpContext.Request.Cookies.Remove(TempDataCookieKey); 

        var rescookie = new HttpCookie(TempDataCookieKey); 
        rescookie.HttpOnly = true; 
        rescookie.Value = ""; 
        rescookie.Expires = new DateTime(2000, 1, 1); //so that the browser will remove the cookie when it receives the request 
        _httpContext.Response.Cookies.Add(rescookie); 
       } 
      } 
     } 
    } 

    public static IDictionary<string, object> DeserializeTempData(string base64EncodedSerializedTempData) 
    { 
     byte[] bytes = Convert.FromBase64String(base64EncodedSerializedTempData); 
     var memStream = new MemoryStream(bytes); 
     var binFormatter = new BinaryFormatter(); 
     return binFormatter.Deserialize(memStream, null) as IDictionary<string, object> /*TempDataDictionary : This returns NULL*/; 
    } 

    public static string SerializeToBase64EncodedString(IDictionary<string, object> values) 
    { 
     MemoryStream memStream = new MemoryStream(); 
     memStream.Seek(0, SeekOrigin.Begin); 
     var binFormatter = new BinaryFormatter(); 
     binFormatter.Serialize(memStream, values); 
     memStream.Seek(0, SeekOrigin.Begin); 
     byte[] bytes = memStream.ToArray(); 
     return Convert.ToBase64String(bytes); 
    } 

    IDictionary<string, object> ITempDataProvider.LoadTempData(ControllerContext controllerContext) 
    { 
     return LoadTempData(controllerContext); 
    } 

    void ITempDataProvider.SaveTempData(ControllerContext controllerContext, IDictionary<string, object> values) 
    { 
     SaveTempData(controllerContext, values); 
    } 
} 
2

Dưới đây là một ví dụ về một giải pháp làm việc mà không cần rất nhiều mã dư thừa. Nó sử dụng Json.NET để tuần tự hóa, nhanh hơn BinaryFormatter + Base64Encoding và cũng tạo ra một chuỗi ngắn hơn nhiều hơn (= ít hơn http trên đầu).

public class CookieTempDataProvider : ITempDataProvider 
{ 
    const string cookieKey = "temp"; 

    public IDictionary<string, object> LoadTempData(ControllerContext controllerContext) 
    { 
     var cookie = controllerContext.HttpContext.Request.Cookies[cookieKey]; 

     if (cookie != null) { 
      return JsonConvert.DeserializeObject<IDictionary<string, object>>(cookie.Value); 
     } 

     return null; 
    } 

    // Method is called after action execution. The dictionary mirrors the contents of TempData. 
    // If there are any values in the dictionary, save it in a cookie. If the dictionary is empty, 
    // remove the cookie if it exists. 
    public void SaveTempData(ControllerContext controllerContext, IDictionary<string, object> values) 
    { 
     var ctx = controllerContext.HttpContext; 

     if (values.Count > 0) { 
      var cookie = new HttpCookie(cookieKey) 
      { 
       HttpOnly = true, 
       Value = JsonConvert.SerializeObject(values) 
      }; 

      ctx.Response.Cookies.Add(cookie); 
     } else if (ctx.Request.Cookies[cookieKey] != null) { 

      // Expire cookie to remove it from browser. 
      ctx.Response.Cookies[cookieKey].Expires = DateTime.Today.AddDays(-1); 
     } 
    } 
} 
+0

bạn nên quấn một số bánh xích xung quanh deserialize của bạn –

4

Có giải pháp tốt hơn bởi Brock Allen trên GitHub sử dụng mã hóa, 2 dạng tuần tự hóa và nén để bảo vệ và tối ưu hóa cookie.

https://github.com/brockallen/CookieTempData

Dưới đây là một liên kết đến các blog về nó:

http://brockallen.com/2012/06/11/cookie-based-tempdata-provider/

Ông cũng có một kỹ thuật tốt sử dụng IControllerFactory để đảm bảo mọi điều khiển được cung cấp với một thể hiện của ITempDataProvider.

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