Friday, December 11, 2009

Running code with elevated previliges

Often it is useful to write code which has the ability to perform tasks that the user executing the code cannot do. For example, you may want to capture feedback from a user through a custom web part and add that feedback to a SharePoint list that the user does not have access to directly. Since server-side code executes in the context of the current user, the attempt to write the list item would fail.

The way around this is to use a method on SPSecurity called RunWithElevatedPrivileges. This method accepts an anonymous delegate which will contain all of the code you want to execute. Any code within this delegate will execute as the system account.

// this code runs in the context of the user
SPWeb web = SPContext.Current.Site.RootWeb;
SPList list = web.Lists["My List"];

// this code will run in the context of the system account
SPSecurity.RunWithElevatedPrivileges(delegate()
{
SPSite rootSite = new SPSite("http://myserver");
SPWeb rootWeb = rootSite.RootWeb;
SPList myList = rootWeb.Lists["My List"];
});

// now we're back to the user context
int itemCount = list.ItemCount;

One important thing to note is that only objects instantiated within the RunWithElevatedPrivileges code block will have the context of the system account. So objects created outside of that will still have the context of the current user - even if they are used within the RunWithElevatedPrivileges block.

// create an object in the context of the user
SPWeb web = SPContext.Current.Web;

// run as system account
SPSecurity.RunWithElevatedPrivileges(delegate()
{
// this will execute as the current user, not the
// system account because it is accessing the web
// object which was instantiated outside of the
// RunWithElevatedPrivileges block
SPList myList = web.Lists["My List"];
});

Event Receivers
RunWithElevatedPrivileges is often used in Event Receivers to perform some sort of automation. Event receiver methods are passed SPItemEventProperties objects which provide easy access to the current list, current list item, current web, etc. However, you cannot use these objects directly within a RunWithElevatedPrivileges block because they were instantiated outside in the context of the user. As a workaround, you can re-create these objects within the context of the system account.

public override void ItemAdded(SPItemEventProperties properties)
{
// start sys account context
SPSecurity.RunWithElevatedPrivileges(delegate()
{
// accessing the list item directly from the properties
// will execute as the end user - not the system account
properties.ListItem["Title"] = "Hello";

// instead, re-instantiate these objects using data from the
// properties, but not the actual objects themselves
SPSite site = new SPSite(properties.SiteId);
SPWeb web = site.OpenWeb(properties.RelativeWebUrl);
SPList list = web.Lists[properties.ListId];
SPListItem item = list.Items.GetItemById(properties.ListItemId);
item["Title"] = "Hello";

item.Update();
}
}

No comments:

Post a Comment