• 包含了很多技巧的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

  • 相关阅读:
    关于微信三点定位法
    PHP 取302跳转后真实 URL 的两种方法
    前端布局神器display:flex
    JS实现document.ready
    为什么无返回值的链表的插入操作头结点一定要用指向指针的指针
    常量字符串和指针
    C语言中指针数组和数组指针的区别
    二维数组简介与使用
    访问者模式
    解释器模式
  • 原文地址:https://www.cnblogs.com/awpatp/p/1664284.html
Copyright © 2020-2023  润新知