包含了很多技巧的SharePoint Event Handler的例子

该例子包含的技巧如下:

1. 如何在Event Handler中获取List Item.

2. 如何impersonate另一个用户, 不使用RunWithElevatedPrivilages. 这里进行了包装, 拷贝类, 直接用就可以.

3. 修改一个item的permissions

4. 在web site中创建一个新的permission role

5. 检查一个role是否存在, 这是一个很棒的trick. 读取SPWeb.RoleDefinitions.Xml, 在其中寻找/Role[@Name='" + roleName + "']匹配的节点. 没找到就是没有.

6. 告诉你如何自己写log的小代码例子.

 

using System;

using System.Globalization;

using System.ComponentModel;

using System.IO;

using System.Data;

using System.Text;

using System.Xml;

using System.Collections;

using System.Configuration;

using System.Diagnostics;

using System.Web;

using System.Security;

using System.Security.Policy;

using System.Security.Principal;

using System.Security.Permissions;

using System.Runtime.InteropServices;

using Microsoft.SharePoint;

namespace SharePointTips.SharePoint.Samples.EventHandlers

{

    /// <summary>

    /// This is the event receiver that traps the item added event of the sharepoint list it is attached to.

    /// </summary>

    class ListItemSecuritySetter:SPItemEventReceiver

    {

        #region constants

        /// <summary>

        /// defines the permission set for editors. 

        /// </summary>

        const SPBasePermissions c_EditorPermissions = SPBasePermissions.EditListItems | SPBasePermissions.ViewListItems;

        /// <summary>

        /// defines the permission set for readers

        /// </summary>

        const SPBasePermissions c_ReaderPermissions = SPBasePermissions.ViewListItems;

        /// <summary>

        /// The name of the role that will be created for the author

        /// </summary>

        const string c_AuthorRoleName = "Item Author and Editor";

        /// <summary>

        /// The name of the role that will be created for the reader

        /// </summary>

        const string c_ReaderRoleName = "Item Reader";

        /// <summary>

        /// Debug mode writes almost every action to the file log. In production switch this to false. 

        /// Recommend changing that to read from a configuration file

        /// </summary>

        const bool DEBUG_MODE = true;

        /// <summary>

        /// The page where the log file will be created. Recommend changing that to read from a configuration file

        /// </summary>

        const string c_logFileFolder = @"c:\temp";        

        #endregion



        #region class properties

        /// <summary>

        /// Returns the name of the log file to be used (file name only - not path)

        /// The string returned will contain {0} and {1} that should be replaced with list name and site name.

        /// </summary>

        private string LogFileName

        {

            get

            {

                return "ListItemSecuritySetter-{0}-{1}-" + DateTime.Now.Year.ToString() + 

                    DateTime.Now.Month.ToString() + DateTime.Now.Day.ToString() + ".htm";

            }

        }



        #endregion



        #region local variables



        HTMLFileLogging log;



        #endregion



        #region event handler event trapping

        /// <summary>

        /// The sharepoint event for ItemAdded

        /// </summary>

        /// <param name="properties"></param>

        public override void ItemAdded(SPItemEventProperties properties)

        {

            //run the default event handlers on the item

            base.ItemAdded(properties);





            //create the log handler object

            log = new HTMLFileLogging(c_logFileFolder, 

                string.Format(LogFileName,properties.ListTitle,properties.OpenWeb().Title) , true, false);

                this.WriteToLog("ItemAdded was triggered",true);

            //if in debug mode, write all the properties in the item to the log

            if(DEBUG_MODE)

                WriteItemPropertiesToLog(properties.ListItem);

            

            this.WriteToLog("Setting permissions", true);

            try

            {

                //impersonate an administrator who can change permissions on list items in the list

                ImpersonationUtility imp = ImpersonationUtility.ImpersonateAdmin();

                //open the spweb object to get the token for the user

                using (SPWeb webOrigUser = properties.OpenWeb())

                {

                    //get the token for the impersonation user (this will get the user that the ImpersonationUtility is using)

                    SPUserToken token = webOrigUser.AllUsers[WindowsIdentity.GetCurrent().Name].UserToken;

                    //reopen the spweb object with the new token - full impersonation!

                    using (SPSite site = new SPSite(properties.SiteId, token))

                    {

                        using (SPWeb web = site.OpenWeb(properties.RelativeWebUrl))

                        {



                            //call the function that changes the permissions on the list item. 

                            //Do not use properties.ListItem since that will break impersonation!

                            SetAuthorAsOnlyEditor(web.Lists[properties.ListId].GetItemById(properties.ListItemId));

                        }

                    }

                }



                

            }

            catch (Exception ex)

            {

                this.WriteToLog("Setting permissions encountered an error: " + ex.Message + Environment.NewLine + ex.ToString(), true);

            }

        }

        

        #endregion



        #region custom functions

        /// <summary>

        /// Loops over the item properties and prints them to the log file. should only be called in debug mode!

        /// </summary>

        /// <param name="item">the list item that is currently handled</param>

        private void WriteItemPropertiesToLog(SPListItem item)

        {

            this.WriteToLog("Item Properties:",false);

            foreach(SPField field in item.Fields)

            {

                try

                {

                    this.WriteToLog(field.Title + " : " + item[field.InternalName].ToString(), false);

                }

                catch { }

            }            

        }

        /// <summary>

        /// Function sets the permission on the list item so that the author has edit permission on the item, 

        /// and all other people with access to the document library can only read.

        /// Relies on the values in the constants c_EditorPermissions and c_ReaderPermissions.

        /// </summary>

        /// <param name="item">the list item that is currently handled</param>

        private void SetAuthorAsOnlyEditor(SPListItem item)

        {

            

            using (SPWeb currentWeb = item.Web)

            {

                this.WriteToLog("Getting author from item", true);

                //get the author from the item. 'Author' is a built-in property, so it should be in all lists.

                string authorValue = item["Author"].ToString();                

                SPFieldUserValue authorUserValue = new SPFieldUserValue(currentWeb, authorValue);

                SPUser authorUser = authorUserValue.User;

                this.WriteToLog("Got author name:'" + authorUser.Name + "', email: '" + authorUser.Email + "'", true);

                

                this.WriteToLog("Breaking role inheritance for the item", true);                

                //break the security of the item from the list, but keep the permissions

                item.BreakRoleInheritance(true);

                //change the permissions of everyone with access to this item so they are readers only (c_ReaderPermissions)

                ChangeItemExistingRoles(item);



                this.WriteToLog("Creating role '" + c_AuthorRoleName + "' in the site if needed", true);

                //create a security definition in the web for an author-editor

                SPRoleDefinition def = CreateRoleInSite(currentWeb,c_AuthorRoleName,c_EditorPermissions);

                this.WriteToLog("Assigning role to the user", true);

                //Set the author user with the permissions defined

                SPRoleAssignment authorRole = new SPRoleAssignment(authorUser.LoginName, 

                    authorUser.Email, authorUser.Name, authorUser.Notes);

                this.WriteToLog("Binding the role assignment of the user to the definition", true);

                authorRole.RoleDefinitionBindings.Add(def);

                this.WriteToLog("Adding the role to the item", true);

                item.RoleAssignments.Add(authorRole);

                this.WriteToLog("Updating the item", true);

                item.Update();

                this.WriteToLog("Success!", true);

            }

        }

        /// <summary>

        /// This function will make everyone with access to the item a reader.

        /// Loops over all the roles that exist in the item, removes the bindings and adds the reader permission definition to them

        /// </summary>

        /// <param name="item">the list item currently handled</param>

        private void ChangeItemExistingRoles(SPListItem item)

        {

            //get, and if necessary create, the reader role

            SPRoleDefinition readerDef = CreateRoleInSite(item.Web, c_ReaderRoleName, c_ReaderPermissions);



            

            foreach (SPRoleAssignment roleAssignment in item.RoleAssignments)

            {

                //delete the existing permissions

                roleAssignment.RoleDefinitionBindings.RemoveAll();

                //add the reader permission

                roleAssignment.RoleDefinitionBindings.Add(readerDef);

                roleAssignment.Update();

                item.Update();



            }

        }

        /// <summary>

        /// Gets and if necessary creates the role in the site.

        /// </summary>

        /// <param name="web">The site where the role should be created</param>

        /// <param name="roleName">The name of the role to create</param>

        /// <param name="permissions">The permission set to give the role. Example: 

        /// SPBasePermissions.EditListItems | SPBasePermissions.ViewListItems</param>

        /// <returns></returns>

        private SPRoleDefinition CreateRoleInSite(SPWeb web,string roleName,SPBasePermissions permissions)

        {

            this.WriteToLog("Checking if role '"+roleName+"' exists in the web", true);

            //check that the role exists

            if (RoleExists(web, roleName))

            {

                this.WriteToLog("Role exists in the web", true);

                //role exists - return it

                return web.RoleDefinitions[roleName];

            }

            else

            {

                //role does not exist in the site-  create it and return.

                this.WriteToLog("Role does not exist in the web. creating a new role", true);

                //Create the role definition in the web by the name specified in c_AuthorRoleName

                SPRoleDefinition def = new SPRoleDefinition();

                def.BasePermissions = permissions;

                def.Name = roleName;

                this.WriteToLog("Adding the role to the FirstUniqueRoleDefinitionWeb", true);

                web.FirstUniqueRoleDefinitionWeb.RoleDefinitions.Add(def);

                this.WriteToLog("Updating the web", true);

                web.FirstUniqueRoleDefinitionWeb.Update();

                web.FirstUniqueRoleDefinitionWeb.Dispose();

                this.WriteToLog("Reopening the current web object", true);

                web = web.Site.OpenWeb();

                this.WriteToLog("Verifying role is in current web", true);

                if (RoleExists(web, roleName))

                    return web.RoleDefinitions[roleName];

                else

                {

                    throw new Exception("Role does not exist?");

                }



            }

        }

        /// <summary>

        /// This function checks the spweb objec to see if a specific role exists (by name)

        /// </summary>

        /// <param name="web">the spweb object for the site to contain the role.</param>

        /// <param name="roleName">the name of the role searched for</param>

        /// <returns></returns>

        private bool RoleExists(SPWeb web, string roleName)

        {

            this.WriteToLog("Loading the RoleDefinitions xml string:", true);

            this.WriteToLog(web.RoleDefinitions.Xml, true);

            //read the xml of the roledefinitions

            XmlDocument doc = new XmlDocument();

            doc.LoadXml(web.RoleDefinitions.Xml);

            this.WriteToLog("Searching for the role in the xml", true);

            //search for the role with the name in the xml

            XmlNode node = doc.SelectSingleNode("//Role[@Name='"+roleName+"']");

            //if the search returned null, the role does not exist

            if (node == null)

                return false;

            else

                return true;

        }

        /// <summary>

        /// writes a message to the log file

        /// </summary>

        /// <param name="message">The message to write</param>

        /// <param name="debugOnly">If true, the message will only get written when the code runs in debug mode.</param>

        private void WriteToLog(string message,bool debugOnly)

        {

            if (DEBUG_MODE || !debugOnly)

                log.WriteToLogFile(message);            

        }

        #endregion

    }

    /// <summary>

    /// Handles simple file logging. Recommend switching to trace log.

    /// </summary>

    class HTMLFileLogging

    {

        #region class properties

        private string logFolderPath = @"c:\logs";

        public string LogFolderPath

        {

            get

            {

                return logFolderPath;

            }

            set

            {

                if (Directory.Exists(value))

                {

                    logFolderPath = value;

                    if (logFolderPath.EndsWith("\\"))

                    {

                        logFolderPath = logFolderPath.Remove(logFolderPath.Length);

                    }

                }

                else

                {

                    throw new DirectoryNotFoundException();

                }

            }

        }

        private string logFileName = "";

        public string LogFileName

        {

            get

            {

                return logFileName;

            }

            set

            {

                logFileName = value;

            }

        }

        public string LogFilePath

        {

            get

            {

                return this.LogFolderPath + "\\" + this.LogFileName;

            }

        }

        

        #endregion

        

        #region CTOR

        /// <summary>

        /// Create a HTMLFileLogging object

        /// </summary>

        /// <param name="folderPath">The path of the folder that will hold the log file (no file name)</param>

        /// <param name="fileName">The name of the file to create</param>

        /// <param name="createPath">When this is set to true and the folder does not exist, the code will create the folder.</param>

        /// <param name="deleteFile">When this is set to true and the file exists, the code will delete the file and create a new one</param>

        public HTMLFileLogging(string folderPath, string fileName, bool createPath, bool deleteFile)

        {

         

            this.LogFileName = fileName;

            

            if (createPath && !Directory.Exists(folderPath))

            {

                Directory.CreateDirectory(folderPath);

            }

            this.LogFolderPath = folderPath;

            if (File.Exists(this.LogFilePath) && deleteFile)

            {

                File.Delete(this.LogFilePath);

            }



        }



        #endregion



        #region custom code

        /// <summary>

        /// Writes a string to the log file. 

        /// </summary>

        /// <param name="message">a string to write. supports html tags.</param>

        public void WriteToLogFile(string message)

        {

            try

            {

                StreamWriter sw = new StreamWriter(this.LogFilePath,true);

                sw.WriteLine("<p>");

                sw.WriteLine("<date>" + DateTime.Now.ToShortDateString()+ "</date> <time>" + 

                    DateTime.Now.ToLongTimeString() + 

                    "</time> <br /> <message>" + message + "</message>");

                sw.WriteLine("</p>");

                sw.Flush();

                sw.Close();

            }

            catch (Exception ex)

            {

            }

        }



        #endregion



    }

    /// <summary>

    /// Thanks to impersonation example of Victor Vogelpoel [Macaw] 

    /// http://dotnetjunkies.com/WebLog/victorv/archive/category/2032.aspx

    /// </summary>

    public sealed class ImpersonationUtility

    {        

        private static string ADMINDOMAINACCOUNT = @"domain\user";//CHANGE THIS!

        private static string ADMINDOMAIN = "domain";//CHANGE THIS!

        private static string ADMINACCOUNT = "user";//CHANGE THIS!

        private static string ADMINPASSWORD = "password";//CHANGE THIS!

        private WindowsImpersonationContext _wiContext;

        public IntPtr token;

        /// <summary>

        /// Private ctor.

        /// </summary>

        private ImpersonationUtility()

        { }

        /// <summary>

        /// Start impersonating the administrator.

        /// </summary>

        /// <returns>an ImpersonationUtility instance.</returns>

        public static ImpersonationUtility ImpersonateAdmin()

        {

            ImpersonationUtility imp = new ImpersonationUtility();

            imp._ImpersonateAdmin();

            return imp;

        }

        /// <summary>

        /// Undo the impersonation.

        /// </summary>

        public void Undo()

        {

            if (this._wiContext != null)

            {

                this._wiContext.Undo();

                this._wiContext = null;

            }

        }

        private void _ImpersonateAdmin()

        {

            token = IntPtr.Zero;

            IntPtr tokenDuplicate = IntPtr.Zero;

            try

            {

                // Only start admin impersonation if we're not the admin...

                if (String.Compare(ADMINDOMAINACCOUNT, WindowsIdentity.GetCurrent().Name, true, CultureInfo.InvariantCulture) != 0)

                {

                    // Temporarily stop the impersonation started by Web.Config.

                    // WindowsIdentity.Impersonate() will store the current identity (the

                    // account of the requestor) and return to the account of the ApplicationPool

                    // which is "DOMAIN\SPAdmin".

                    this._wiContext = WindowsIdentity.Impersonate(IntPtr.Zero);

                    // But somehow the reverted account "DOMAIN\SPAdmin" still does

                    // not have enough privileges to access SharePoint objects, so

                    // we're logging in DOMAIN\SPAdmin again...

                    if (NativeMethods.LogonUserA(ADMINACCOUNT, ADMINDOMAIN, ADMINPASSWORD,

                        NativeMethods.LOGON32_LOGON_INTERACTIVE,

                        NativeMethods.LOGON32_PROVIDER_DEFAULT, ref token) != 0)

                    {

                        if (NativeMethods.DuplicateToken(token, 2, ref tokenDuplicate) != 0)

                        {

                            WindowsIdentity wi = new WindowsIdentity(tokenDuplicate);

                            // NOTE: Impersonate may fail if account that tries to impersonate does

                            // not hold the "Impersonate after Authentication" privilege

                            // See local security policy - user rights assignment.

                            // Note that the ImpersonationContext from the Impersonate() call

                            // is ignored. Upon the Undo() call, the original account

                            // will be reinstated.

                            wi.Impersonate();

                        }

                        else

                        {

                            throw new Win32Exception(Marshal.GetLastWin32Error(),

                            "Impersonation: Error duplicating token after logon for user \"DOMAIN\\SPAdmin\"");

                        }

                    }

                    else

                    {

                        throw new Win32Exception(Marshal.GetLastWin32Error(),

                        "Impersonation: Error logging on user \"DOMAIN\\SPAdmin\"");

                    }

                }

            }

            finally

            {

                if (token != IntPtr.Zero)

                    NativeMethods.CloseHandle(token);

                if (tokenDuplicate != IntPtr.Zero)

                    NativeMethods.CloseHandle(tokenDuplicate);

            }

        }

    }

    /// <summary>

    /// Thanks to impersonation example of Victor Vogelpoel [Macaw] 

    /// http://dotnetjunkies.com/WebLog/victorv/archive/category/2032.aspx

    /// </summary>

    internal sealed class NativeMethods

    {

        private NativeMethods() { }



        [DllImport("kernel32.dll", CharSet = CharSet.Auto)]

        public static extern bool CloseHandle(IntPtr handle);



        public const int LOGON32_PROVIDER_DEFAULT = 0;

        public const int LOGON32_LOGON_INTERACTIVE = 2;

        public const int LOGON32_LOGON_NETWORK = 3;



        [DllImport("advapi32.dll")]

        public static extern int LogonUserA(String lpszUserName,

        String lpszDomain,

        String lpszPassword,

        int dwLogonType,

        int dwLogonProvider,

        ref IntPtr phToken);



        [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]

        public static extern int DuplicateToken(IntPtr hToken,

        int impersonationLevel,

        ref IntPtr hNewToken);





        [DllImport("advapi32.dll", CharSet = CharSet.Auto, SetLastError = true)]

        public static extern bool RevertToSelf();

    } 

 

摘自:

Sample Event Handler to set Permissions

http://www.sharepoint-tips.com/2007/03/sample-event-handler-to-set-permissions.html

你可能感兴趣的:(SharePoint)