在使用提升权限运行时首选哪一种方法?
第一种方法:
SPSecurity.RunWithElevatedPrivileges(delegate()
{
using (SPSite curSite = new SPSite(SPContext.Current.Site.ID))
{
using (SPWeb web = curSite.OpenWeb(SPContext.Current.Web.ID))
{
try
{
web.AllowUnsafeUpdates = true;
\\ do your stuff
}
catch (Exception e)
{
}
finally
{
web.AllowUnsafeUpdates = false;
web.Dispose();
}
}
}
});
第二种方法:
SPSite oSite = SPContext.Current.Site;
SPWeb oWeb = SPContext.Current.Web;
SPSecurity.RunWithElevatedPrivileges(delegate()
{
using (SPSite curSite = new SPSite(oSite.ID))
{
using (SPWeb web = curSite.OpenWeb(oWeb.ID))
{
try
{
web.AllowUnsafeUpdates = true;
\\ do your stuff
}
catch (Exception e)
{
}
finally
{
web.AllowUnsafeUpdates = false;
web.Dispose();
oWeb.Dispose();
oSite.Dispose();
}
}
}
});
是否有人怀疑“正在更新的网页被外部进程更改”例外?
答案 0 :(得分:6)
首先,您应该在提升代码之前拨打SPWeb.ValidateFormDigest()
或SPUtility.ValidateFormDigest()
。这将消除GET请求不允许的不安全更新,并避免您设置AllowUnsafeUpdate属性。
其次,正如Nigel Whatling所提到的,你在第二个代码中处理了上下文对象。你不必处置它们。简单来说,只处理你自己实例化的对象。像您这样的代码可能会导致副作用,因为其他SharePoint组件可能需要访问SPContext.Current.XX对象。这可能是您问题的根源。
第三,当您使用using构造时,您不必对使用标头中设置的变量调用.Dispose()。实际上,using构造的作用(实际上是好处)是你不必关心处理对象。一旦块代码退出,即使存在异常,也会在对象上调用.Dispose()方法。
总而言之,您的代码应更改为:
SPUtility.ValidateFormDigest();
SPSecurity.RunWithElevatedPrivileges(delegate()
{
using (SPSite curSite = new SPSite(SPContext.Current.Site.ID))
{
using (SPWeb web = curSite.OpenWeb(SPContext.Current.Web.ID))
{
// Do stuff here
}
}
});
附注:要提升代码,您有两种选择。您在此处使用的那个(调用SPSecurity.RunWithElevatedPrivileges
)或使用SystemAccount标记实例化新的SPSite:
using (SPSite curSite = new SPSite(
SPContext.Current.Site.ID,
SPContext.Current.Site.SystemAccount.UserToken
))
{
using (SPWeb web = curSite.OpenWeb(SPContext.Current.Web.ID))
{
// Do stuff here
}
}
这将允许您在Web应用程序之外运行提升的代码。
您还应该考虑使用一些实用程序代码以更实用的方式包装此类操作。我习惯使用这样的代码:
public static void RunWithElevatedPrivileges(this SPWeb web, Action<SPSite, SPWeb> codeToRunElevated)
{
if (CheckIfElevated(web))
{
codeToRunElevated(web.Site, web);
}
else
{
using (var elevatedSite = new SPSite(web.Site.ID, web.AllUsers["SHAREPOINT\\system"].UserToken))
{
using (var elevatedWeb = elevatedSite.OpenWeb(web.ID))
{
codeToRunElevated(elevatedSite, elevatedWeb);
}
}
}
}
/// <summary>
/// Indicates whether the context has been elevated
/// </summary>
public static bool CheckIfElevated(SPWeb web)
{
return web.CurrentUser.LoginName == "SHAREPOINT\\system";
}
使用此类代码,您只需在代码中的某处执行操作:
SPContext.Current.Web.RunWithElevatedPrivileges((elevatedSite, elevatedWeb)=>{
// do something will all privileges
});
答案 1 :(得分:1)
两种方法几乎完全相同。除了在第二种方法中,您还要处理当前上下文的SPWeb和SPSite对象 - 这是您不应该做的事情。是否会在web.Update()调用上抛出异常?问题出在“做你的东西”代码中吗?