2008-10-17 33 views
14

Cho đến nay, trong nghiên cứu của tôi, tôi đã thấy rằng nó là không khôn ngoan để thiết lập AllowUnsafeUpdates trên hoạt động yêu cầu GET để tránh viết mã chéo trang web. Nhưng, nếu nó được yêu cầu để cho phép điều này, cách thích hợp để xử lý tình hình để giảm thiểu bất kỳ tiếp xúc là gì?Mô hình tốt nhất cho AllowUnsafeUpdates

Đây là dự đoán đầu tiên tốt nhất của tôi về mẫu đáng tin cậy nếu bạn hoàn toàn cần cho phép cập nhật trang web hoặc trang web trên yêu cầu GET.

Thực tiễn tốt nhất?

protected override void OnLoad(System.EventArgs e) 
{ 
    if(Request.HttpMethod == "POST") 
    { 
     SPUtility.ValidateFormDigest(); 
     // will automatically set AllowSafeUpdates to true 
    } 

    // If not a POST then AllowUnsafeUpdates should be used only 
    // at the point of update and reset immediately after finished 

    // NOTE: Is this true? How is cross-site scripting used on GET 
    // and what mitigates the vulnerability? 
} 

// Point of item update 

    using(SPSite site = new SPSite(SPContext.Current.Site.Url, SPContext.Current.Site.SystemAccount.UserToken)) 
    { 
     using (SPWeb web = site.RootWeb) 
     { 
      bool allowUpdates = web.AllowUnsafeUpdates; //store original value 
      web.AllowUnsafeUpdates = true; 

      //... Do something and call Update() ... 

      web.AllowUnsafeUpdates = allowUpdates; //restore original value 

     } 
    } 

Phản hồi về mẫu tốt nhất được đánh giá cao.

Trả lời

1

Bạn không nên nhớ giá trị trước đó của các cập nhật cho phép không an toàn.

Tôi muốn kết thúc cuộc gọi xung quanh số lượng mã tối thiểu có thể, để các cuộc gọi lồng nhau vào nó sẽ không xảy ra.

Sau đó, bạn chỉ có thể biến nó thành false sau đó.

+0

Nó không về lồng nhau, đó là về ghi nhớ trạng thái trước và đảm bảo rằng nhà nước còn lại không thay đổi cho mã đó là chạy trực tiếp sau. – soniiic

+1

Tôi không hiểu tại sao bạn không phải lúc nào cũng đặt nó trở lại thành false, vì đó là trạng thái an toàn nhất? Tôi thà giữ hành động không an toàn nguyên tử và gọi allowunsafeupdates chỉ khi cần thiết. –

7

Nếu bạn đang thực hiện bất kỳ thao tác nào sửa đổi thứ gì đó, thì bất kỳ ai có thể thuyết phục người dùng nhấp vào liên kết đều có thể thực hiện thao tác đó. Ví dụ: giả sử rằng bạn có yêu cầu GET đến trang cho phép người dùng thêm quản trị viên vào trang web và người dùng nhấp vào một liên kết đến trang thực hiện Phản hồi.Redirect ("http://yourserver/_layouts/admin.aspx?operation=addAdministrator&username=attackerNameHere").

Mặc dù POST bình thường không cung cấp nhiều biện pháp bảo vệ chống lại điều này (không có gì ngăn người khác có phương thức biểu mẫu < = "post" action = "http: //yourserver/_layouts/admin.aspx">), SharePoint có một khái niệm về việc phân loại biểu mẫu, chứa thông tin về yêu cầu trước đó tạo ra bài đăng (bao gồm tên của người dùng). Điều này làm giảm dấu chân cho loại tấn công này một cách đáng kể.

Lần duy nhất vấn đề bảo mật cho AllowUnsafeUpdates trên GET là nếu bạn không nhận dữ liệu nhập từ người dùng. Ví dụ, nếu bạn có một phần web mà cũng đăng nhập vào một danh sách, sau đó không có lỗ hổng bảo mật tiếp xúc.

Chỉnh sửa: Nếu bạn định sử dụng AllowUnsafeUpdates, bạn không cần phải đặt lại giá trị trước đó. Nó không bị kéo dài. Nó chỉ là một cái gì đó bạn cần phải đặt trên một đối tượng SPWeb trước khi thực hiện cập nhật từ một GET (hoặc các trường hợp khác)

+1

Đây là một điểm quan trọng để nhấn mạnh: "Lần duy nhất không phải là vấn đề bảo mật đối với AllowUnsafeUpdates trên GET là nếu bạn không dùng đầu vào từ người dùng. Ví dụ: nếu bạn có một phần web cũng đăng nhập lượt truy cập vào danh sách, sau đó không có lỗ hổng bảo mật nào bị lộ. " – webwires

1

Tôi sử dụng một lớp wrapper để xử lý hầu hết các thao tác của SPWeb đối tượng. Điều này giúp tôi nhớ đóng web và điều này giúp giảm bớt các vấn đề của cài đặt không an toàn. Đó là một chút cồng kềnh, như tôi đã vá trên các nhà thầu mới và các thành viên. nhưng, sau đó một lần nữa; đây là lớp SPWeb.

Cách sử dụng:

using (WebWrapper wrapper = new WebWrapper("http://localhost")) 
      { 
       wrapper.AllowUnsafeUpdates(); 

       //Do work on wrapper. 
      } 

Định nghĩa lớp:

using System; 
using System.Collections.Specialized; 
using System.Data; 
using System.Diagnostics; 
using System.Globalization; 
using System.Runtime.Serialization; 
using Microsoft.SharePoint; 
using Microsoft.SharePoint.Administration; 

namespace Skaar.SharePoint.Customization 
{ 
    /// <summary> 
    /// A wrapper for a <see cref="SPWeb"/> object. 
    /// <remarks>Closes web object on Dispose if applicable.</remarks> 
    /// </summary> 
    [Serializable] 
    [DebuggerDisplay("{Uri} Unsafe:{AllowUnsafeUpdatesSetting} Update:{UpdatePending}")] 
    public sealed class WebWrapper : IDisposable, IDeserializationCallback, IEquatable<WebWrapper> 
    { 
     [NonSerialized] private bool unsafeUpdatesSetting; 

     [NonSerialized] private SPWeb web; 

     /// <summary> 
     /// Determines if the inner web object should be closed. 
     /// </summary> 
     [NonSerialized] private bool webShouldBeClosed; 

     /// <summary> 
     /// This value is used in serialization to restore <see cref="Web"/>. 
     /// </summary> 
     private string webUrl; 

     /// <summary> 
     /// Creates a new wrapper object. 
     /// </summary> 
     /// <param name="web">A web that should be closed/disposed when done.</param> 
     public WebWrapper(SPWeb web) : this(web, true) 
     { 
     } 

     /// <summary> 
     /// Creates a new wrapper object. 
     /// </summary> 
     /// <param name="web">An inner web object</param> 
     /// <param name="webShouldBeClosed">If true, the web object is closed in the <see cref="Dispose()"/> method.</param> 
     public WebWrapper(SPWeb web, bool webShouldBeClosed) 
     { 
      setWeb(web, webShouldBeClosed); 
     } 

     /// <summary> 
     /// Creates a new wrapper object. 
     /// </summary> 
     /// <param name="webAddress">The address to a web.</param> 
     public WebWrapper(Uri webAddress) 
     { 
      using (SPSite site = new SPSite(webAddress.ToString())) 
      { 
       string relativeUrl = renderWebRootRelativeUrl(webAddress); 
       if (relativeUrl == null) 
       { 
        setWeb(site.OpenWeb(), true); 
       } 
       else 
       { 
        setWeb(site.OpenWeb(relativeUrl), true); 
       } 
      } 
     } 

     private string renderWebRootRelativeUrl(Uri address) 
     { 
      for (int i = 0; i < address.Segments.Length; i++) 
      { 
       string segment = address.Segments[i]; 
       if (string.Equals(segment, "_layouts/")) 
       { 
        string newUrl=string.Join(null, address.Segments, 0, i).Trim('/'); 
        return newUrl; 
       } 
      } 
      return null; 
     } 

     /// <summary> 
     /// If true, <see cref="SPWeb.Update"/> will be called in <see cref="Dispose()"/>. 
     /// </summary> 
     public bool UpdatePending { get; private set; } 

     /// <summary> 
     /// The setting of the inner web (<see cref="SPWeb.AllowUnsafeUpdates"/>) 
     /// </summary> 
     public bool AllowUnsafeUpdatesSetting 
     { 
      get { return Web.AllowUnsafeUpdates; } 
     } 

     /// <summary> 
     /// The inner object. 
     /// </summary> 
     /// <exception cref="ObjectDisposedException">Exception is thrown if <see cref="IsDisposed"/> is true.</exception> 
     public SPWeb Web 
     { 
      get 
      { 
       if(IsDisposed) 
       { 
        throw new ObjectDisposedException("Web wrapper is disposed."); 
       } 
       return web; 
      } 
     } 

     /// <summary> 
     /// The address of the <see cref="Web"/> wrapped as a <see cref="Uri"/> object. 
     /// </summary> 
     public Uri Uri 
     { 
      get { return new Uri(Web.Url); } 
     } 

     /// <summary> 
     /// The address of the <see cref="Web"/> wrapped as a <see cref="Uri"/> object. 
     /// </summary> 
     public Uri GetUri(SPUrlZone zone) 
     { 
      return Site.WebApplication.GetResponseUri(zone, Uri.AbsolutePath); 
     } 

     /// <summary> 
     /// Creates a wrapper around the context web. 
     /// <remarks>The web will not be closed when wrapper is disposed. Returns null if context is unavailable.</remarks> 
     /// </summary> 
     public static WebWrapper Context 
     { 
      get 
      { 
       return SPContext.Current==null?null:new WebWrapper(SPContext.Current.Web, false); 
      } 
     } 

     /// <summary> 
     /// This is a static property wrapping of 
     /// the <see cref="CloneOf(SPWeb)"/> method, using 
     /// the <see cref="SPContext"/> current web as 
     /// parameter. 
     /// <remarks>Returns null if context is unavailable.</remarks> 
     /// </summary> 
     public static WebWrapper CloneOfContext 
     { 
      get 
      { 
       if (SPContext.Current != null) 
       { 
        SPWeb contextWeb = SPContext.Current.Web; 
        return CloneOf(contextWeb); 
       } 
       return null; 
      } 
     } 

     /// <summary> 
     /// Returns the <see cref="SPWeb.Exists"/> property of the <see cref="Web"/> object. 
     /// </summary> 
     public bool Exists 
     { 
      get { return Web != null && Web.Exists; } 
     } 

     /// <summary> 
     /// Gets the <see cref="SPSite"/> object of <see cref="Web"/>. 
     /// </summary> 
     /// <remarks>This object should not be closed by user code.</remarks> 
     public SPSite Site 
     { 
      get { return web.Site; } 
     } 

     /// <summary> 
     /// Gets the owner defined in <see cref="SPSite.Owner"/>. 
     /// </summary> 
     public SPUser Owner 
     { 
      get 
      { 
       return Site.Owner; 
      } 
     } 

     /// <summary> 
     /// Returns a context of the inner <see cref="Web"/>. 
     /// </summary> 
     public SPContext ContextOfWeb 
     { 
      get { return SPContext.GetContext(web); } 
     } 

     /// <summary> 
     /// Gets the language of <see cref="Web"/>. 
     /// </summary> 
     public CultureInfo Locale 
     { 
      get { return Web.Locale; } 
     } 

     /// <summary> 
     /// Gets the language of the root web. 
     /// </summary> 
     public CultureInfo LocaleOfRoot 
     { 
      get 
      { 
       using (WebWrapper root = Root) 
       { 
        return root.Locale; 
       } 
      } 
     } 

     /// <summary> 
     /// Returns a new <see cref="WebWrapper"/> wrapping the root <see cref="SPWeb"/> of this. 
     /// </summary> 
     public WebWrapper Root 
     { 
      get 
      { 
       if (webShouldBeClosed) 
        using (SPSite site = Site) 
        { 
         return new WebWrapper(site.RootWeb); 
        } 
       return new WebWrapper(Site.RootWeb); 
      } 
     } 

     /// <summary> 
     /// A wrapper for <see cref="SPWeb.Title"/>. 
     /// </summary> 
     public string Title 
     { 
      get { return Web.Title; } 
      set { Web.Title = value; } 
     } 

     /// <summary> 
     /// A wrapper for <see cref="SPWeb.ID"/>. 
     /// </summary> 
     public Guid ID 
     { 
      get { return Web.ID; } 
     } 

     #region Web Properties 

     [NonSerialized] private bool updatePropertiesPending; 

     /// <summary> 
     /// A wrapper method to <see cref="Web"/> object's <see cref="SPWeb.Properties"/> indexer. 
     /// </summary> 
     /// <param name="key">The key to use when fetching property value.</param> 
     /// <returns>A string containing the value.</returns> 
     public string GetProperty(string key) 
     { 
      return Web.Properties[key]; 
     } 

     /// <summary> 
     /// Sets the value in the <see cref="Web"/> object's <see cref="SPWeb.Properties"/>. Creates a new key, or updates an existing as needed. 
     /// </summary> 
     /// <param name="key">The key to use when storing the property value.</param> 
     /// <param name="value">The value to set in the key.</param> 
     /// <remarks>The property <see cref="UpdatePending"/> is set to true.</remarks> 
     public void SetProperty(string key, string value) 
     { 
      if (!Web.Properties.ContainsKey(key)) 
      { 
       Web.Properties.Add(key, value); 
      } 
      else 
      { 
       Web.Properties[key] = value; 
      } 
      updatePropertiesPending = true; 
     } 

     #endregion 

     #region IDeserializationCallback Members 

     ///<summary> 
     ///Runs when the entire object graph has been deserialized. 
     ///</summary> 
     /// 
     ///<param name="sender">The object that initiated the callback. The functionality for this parameter is not currently implemented. </param> 
     public void OnDeserialization(object sender) 
     { 
      using (SPSite site = new SPSite(webUrl)) 
      { 
       setWeb(site.OpenWeb(), true); 
      } 
     } 

     #endregion 

     #region IDisposable Members 

     ///<summary> 
     ///Closes inner web object if appropriate. 
     ///</summary> 
     ///<filterpriority>2</filterpriority> 
     public void Dispose() 
     { 
      Dispose(true); 
      GC.SuppressFinalize(this); 
     } 

     public void Dispose(bool isDisposing) 
     { 
      if (IsDisposed) return; 
      if (isDisposing) 
      { 
       doDisposeOfWeb(); 
       IsDisposed = true; 
      } 
     } 

     #endregion 

     /// <summary> 
     /// Value is true if <see cref="Dispose()"/> method has been called. Object is not in a usable state. 
     /// </summary> 
     internal bool IsDisposed 
     { 
      get; private set; 
     } 

     #region IEquatable<WebWrapper> Members 

     /// <summary> 
     /// This tests whether the two objects wraps the same web. It may however be two different instances of the same web. 
     /// </summary> 
     /// <param name="other">Another wrapper object.</param> 
     /// <returns>True if <see cref="Uri"/> equals, false otherwise.</returns> 
     public bool Equals(WebWrapper other) 
     { 
      if (other == null) 
      { 
       return false; 
      } 
      return Uri.Equals(other.Uri); 
     } 

     #endregion 

     /// <summary> 
     /// Reopens the inner <see cref="SPWeb"/> object. May be used when web object needs to be rereferenced in a new security context. 
     /// </summary> 
     public void ReOpen() 
     { 
      bool unsafeSetting = AllowUnsafeUpdatesSetting; 
      using (SPSite site = new SPSite(Web.Url)) 
      { 
       SPWeb newWeb = site.OpenWeb(); 
       doDisposeOfWeb(); 
       web = newWeb; 
       web.AllowUnsafeUpdates = unsafeSetting; 
       unsafeUpdatesSetting = false; 
       webShouldBeClosed = true; 
      } 
     } 

     private void doDisposeOfWeb() 
     { 
      if (Web == null) return; 
      Update(true); 
      if (webShouldBeClosed) 
      { 
       Web.Close(); 
      } 
      else if (Web.Exists) 
      { 
       Web.AllowUnsafeUpdates = unsafeUpdatesSetting; 
      } 
      web = null; 
     } 

     /// <summary> 
     /// Calls <see cref="SPWeb.Update"/> on the <see cref="Web"/> object. 
     /// </summary> 
     public void Update() 
     { 
      Update(false); 
     } 

     /// <summary> 
     /// Sets <see cref="UpdatePending"/> to <c>true</c>. 
     /// </summary> 
     public void SetUpdatePending() 
     { 
      UpdatePending = true; 
     } 

     /// <summary> 
     /// Calls <see cref="SPWeb.Update"/> on the <see cref="Web"/> object. 
     /// <param name="onlyIfPending">If true, update will depend on state of the <see cref="UpdatePending"/> property.</param> 
     /// </summary> 
     public void Update(bool onlyIfPending) 
     { 
      if (onlyIfPending) 
      { 
       if (updatePropertiesPending) 
       { 
        Web.Properties.Update(); 
        updatePropertiesPending = false; 
       } 
       if (UpdatePending) 
       { 
        Web.Update(); 
        UpdatePending = false; 
       } 
      } 
      else 
      { 
       Web.Update(); 
       UpdatePending = false; 
      } 
     } 

     /// <summary> 
     /// Returns the list from <see cref="Web"/> with <see cref="SPList.Title"/> equal to <see cref="title"/>. 
     /// </summary> 
     /// <param name="title">The <see cref="SPList.Title"/> of an existing list.</param> 
     /// <returns>The first list found with the given title, or null, if no list is found.</returns> 
     public SPList GetList(string title) 
     { 
      foreach (SPList list in Web.Lists) 
      { 
       if (list.Title == title) 
       { 
        return list; 
       } 
      } 
      return null; 
     } 
     /// <summary> 
     /// A wrapper method to the <see cref="Web"/> object's <see cref="SPWeb.Lists"/> indexer. 
     /// </summary> 
     /// <param name="id">The id of the list to return.</param> 
     /// <returns>The list with the supplied id.</returns> 
     public SPList GetList(Guid id) 
     { 
      return Web.Lists[id]; 
     } 

     private void setWeb(SPWeb innerWeb, bool shouldBeClosed) 
     { 
      if (innerWeb == null || !innerWeb.Exists) 
      { 
       throw new ArgumentException("Web does not exist", "innerWeb"); 
      } 
      web = innerWeb; 
      webShouldBeClosed = shouldBeClosed; 
      unsafeUpdatesSetting = innerWeb.AllowUnsafeUpdates; 
      AllowUnsafeUpdates(); 
      webUrl = web.Url; 
     } 

     /// <summary> 
     /// Creates a new <see cref="SPWeb"/> object using the 
     /// url of the <see cref="web"/> parameter and wraps it 
     /// in a new wrapper object. The web will be 
     /// closed when the wrapper is disposed. 
     /// The cloning is done using the <see cref="SPWeb.Url"/>, thus no security context is transferred to the new web. 
     /// </summary> 
     /// <remarks>Use this to create a clone of the context web.</remarks> 
     /// <param name="web">The web to clone.</param> 
     /// <returns>A new wrapper object.</returns> 
     public static WebWrapper CloneOf(SPWeb web) 
     { 
      using (SPSite site = new SPSite(web.Url)) 
      { 
       return new WebWrapper(site.OpenWeb()); 
      } 
     } 


     /// <summary> 
     /// Creates a new <see cref="SPWeb"/> object using the 
     /// <see cref="Web"/> of the <see cref="web"/> parameter and wraps it 
     /// in a new wrapper object. The web will be 
     /// closed when the wrapper is disposed. 
     /// </summary> 
     /// <remarks>Use this to create a clone of the context web.</remarks> 
     /// <param name="web">The wrapper to clone.</param> 
     /// <returns>A new wrapper object.</returns> 
     public static WebWrapper CloneOf(WebWrapper web) 
     { 
      return CloneOf(web.Web); 
     } 

     /// <summary> 
     /// Sets the AllowUnsafeUpdates property to true on the 
     /// wrapped web object. 
     /// <remarks> 
     /// The setting is resat back in the dispose method, unless the 
     /// web itself is closed. 
     /// </remarks> 
     /// </summary> 
     public void AllowUnsafeUpdates() 
     { 
      Web.AllowUnsafeUpdates = true; 
     } 

     /// <summary> 
     /// Returns the url of the inner web. 
     /// </summary> 
     /// <returns>A value that equals <see cref="Web"/> <see cref="SPWeb.Url"/> property.</returns> 
     public override string ToString() 
     { 
      return webUrl; 
     } 

     /// <summary> 
     /// Returns a new <see cref="WebWrapper"/> object wrapping a new copy of the inner <see cref="Web"/> object. 
     /// The cloning is done using the <see cref="SPWeb.Url"/>, thus no security context is transferred to the new web. 
     /// </summary> 
     /// <remarks>The static method <see cref="CloneOf(SPWeb)"/> is used on the <see cref="Web"/> property.</remarks> 
     /// <returns>A new wrapper.</returns> 
     public WebWrapper Clone() 
     { 
      return CloneOf(Web); 
     } 

     /// <summary> 
     /// Implicitly wraps the web object in a <see cref="WebWrapper"/> object. 
     /// </summary> 
     /// <param name="web">The web to wrap.</param> 
     /// <returns>A new wrapper object. The original web may be accessed through the <see cref="Web"/> property.</returns> 
     public static implicit operator WebWrapper(SPWeb web) 
     { 
      return new WebWrapper(web, false); 
     } 

     /// <summary> 
     /// Explicitly extracts the <see cref="Web"/> value from the <see cref="wrapper"/>. 
     /// </summary> 
     /// <param name="wrapper">The object wrapping the <see cref="SPWeb"/> to extract.</param> 
     /// <returns>The inner <see cref="Web"/> of <see cref="wrapper"/>.</returns> 
     /// <remarks>The returned <see cref="SPWeb"/> object should be properly disposed after use.</remarks> 
     public static explicit operator SPWeb(WebWrapper wrapper) 
     { 
      wrapper.DoNotDisposeInnerWeb(); 
      return wrapper.Web; 
     } 

     /// <summary> 
     /// Wrapper method for <see cref="SPWeb.GetList"/> on <see cref="Web"/> object. 
     /// </summary> 
     /// <param name="uri">A site relative uri to the list.</param> 
     /// <returns>A list if found.</returns> 
     public SPList GetList(Uri uri) 
     { 
      return web.GetList(uri.ToString()); 
     } 

     /// <summary> 
     /// Wrapper method for <see cref="SPWeb.GetSiteData"/> on <see cref="Web"/> object. 
     /// </summary> 
     /// <returns>The results of the query,</returns> 
     public DataTable GetSiteData(SPSiteDataQuery query) 
     { 
      return Web.GetSiteData(query); 
     } 

     /// <summary> 
     /// Creates a new <see cref="SPWeb"/> as a sub web to this. 
     /// </summary> 
     /// <param name="url">The proposed local url of the new web. The nearest available is selected.</param> 
     /// <param name="name">The title of the new web.</param> 
     /// <param name="description">The description of the new web.</param> 
     /// <param name="language">The language of the new web. <remarks>If the language is not supported, the language of this is used.</remarks></param> 
     /// <param name="template">The site template to use.</param> 
     /// <returns>The new web wrapped in a new <see cref="WebWrapper"/> object.</returns> 
     [DebuggerStepThrough] 
     //debugger step through is to prevent this method to break when debugging, as it throws exceptions by [poor] design. 
     public WebWrapper CreateSubWeb(string url, string name, string description, uint language, 
             string template) 
     { 
      SPWeb newWeb; 
      try 
      { 
       newWeb = Web.Webs.Add(findSuitableWebUrl(url), name, description, language, template, true, false); 
      } 
      catch (SPException err) 
      { 
       if (err.ErrorCode == -2130575266) 
       { 
        //language not supported. Fallback to parent web language 
        newWeb = Web.Webs.Add(findSuitableWebUrl(url), name, description, Web.Language, template, true, 
              false); 
       } 
       else 
        throw; 
      } 
      return new WebWrapper(newWeb); 
     } 

     private string findSuitableWebUrl(string proposedName) 
     { 
      StringCollection names = new StringCollection(); 
      names.AddRange(Web.Webs.Names); 
      int suffixIndex = 0; 
      const int maxIterations = 100000; 
      string name = proposedName; 
      while (names.Contains(name) && suffixIndex < maxIterations) 
      { 
       name = string.Format("{0}_{1}", proposedName, suffixIndex++); 
      } 
      return name; 
     } 

     /// <summary> 
     /// Calling this method will inhibit the default behaviour of closing the web on disposal. 
     /// </summary> 
     /// <remarks>Use with caution.</remarks> 
     internal void DoNotDisposeInnerWeb() 
     { 
      webShouldBeClosed = false; 
     } 

    } 
} 
+0

cảm ơn bạn, luôn luôn tốt nhất của nó để sử dụng wrapper –

4

Một cách sạch để thực hiện sẽ được sử dụng một sự kết hợp của phương pháp khuyến nông và các đại biểu vô danh như vậy:

public static void DoUnsafeUpdate(this SPWeb web, Action action) 
{ 
    bool allowUnsafeUpdates = web.AllowUnsafeUpdates; 
    web.AllowUnsafeUpdates = true; 
    action(); 
    web.AllowUnsafeUpdates = allowUnsafeUpdates; 
} 

Sử dụng phương pháp mở rộng ở trên, sau đó bạn có thể thực hiện hành động "cập nhật không an toàn" như sau:

var web = SPContext.Current.Web; 
web.DoUnsafeUpdate(delegate() 
{ 
    // Put your "unsafe update" code here 
}); 
5

Tôi hơi sẽ sửa đổi đại biểu Trent để chấp nhận các trang web để cập nhật:

public static void DoUnsafeUpdate(this SPWeb web, Action<SPWeb> action) 
{ 
    try 
    { 
     web.AllowUnsafeUpdates = true; 
     action(web); 
    } 
    finally 
    { 
     web.AllowUnsafeUpdates = false; 
    } 
} 

Và sau đó mở rộng HttpContext để đóng gói xác minh của các hình thức tiêu hóa, với một tùy chọn để nâng cao bằng cách sử dụng technique described here:

public static void DoUnsafeUpdate(this HttpContext context, Action<SPWeb> action, bool elevated) 
{ 
    SPWeb web = SPControl.GetContextWeb(context); 
    if (!context.Request.HttpMethod.Equals("POST", StringComparison.Ordinal) 
     || web.ValidateFormDigest()) 
     throw new SPException("Error validating postback digest"); 

    if (elevated) 
     web.RunAsSystem(w => w.DoUnsafeUpdate(action)); 
    else 
     web.DoUnsafeUpdate(action); 
} 

Cách sử dụng:

protected override void OnLoad(System.EventArgs e) 
{ 
    Context.DoUnsafeUpdate(web => 
    { 
     // Update elevated web 
    }, true); 
} 
2

Đối AllowUnsafeUpdates, tôi theo quy trình này: các cuộc gọi

if(HttpContext.Current is null) 
{ 
    Do nothing, no need to set AllowUnsafeUpdates to true nor 
    to call ValidateFormDigest() because update will be carried out 
} 
else // HttpContext.Current is NOT null 
{ 
    if(SPContext.Current is null) 
    { 
    Need to set AllowUnsafeUpdates to true 
    } 
    else // SPContext.Current is NOT null 
    { 
    Call ValidateFormDigest() 
    } 
} 
+1

Sẽ gây ra điều kiện thứ hai '(HttpContext.Current! = Null && SPContext.Current == null)' là đúng? – vitule

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