设为首页 收藏本站
查看: 480|回复: 0

[经验分享] 包含了很多技巧的SharePoint Event Handler的例子

[复制链接]

尚未签到

发表于 2015-9-29 08:44:01 | 显示全部楼层 |阅读模式
  该例子包含的技巧如下:
  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

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-120223-1-1.html 上篇帖子: SharePoint Learning Kit系列索引 下篇帖子: SharePoint 2013 图像呈现形式介绍
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表