今天接到一个需求,是需要在用户的个人信息里添加工号以便和另外一个系统接口(那个系统是用员工工号作为登录名),用户在登录的时候必须强制填写完工号信息才可以访问其他页面。
开始想的比较简单:
1. 在UserProfile里添加自定义的属性"EmployeeNo"
2. 在用户登陆时,先判定用户是否有工号,如果没有则跳到一个页面进行填写; 如果有则不做任何处理
3. 创建一个webpart,用于输入工号信息并更新UserProfile
第一步: 添加"EmployeeNo"属性:
这一步比较简单,SSP --> "User Profile and Properties" --> "Add Profile Property". 里面有一些细节的设定,要根据实
际需求去填充。
第二步: 判定用户是否有工号
因为采用的是Windows验证,所以用户的入口链接是不固定的。 我现在会的方法就是在对应的Global.asax页面里重写相应的事
件。
因为需要在用户身份验证通过以后才能获取到用户的信息,所以开始选择了Application_PreRequestHandlerExecute:在将请
求发送到服务于请求的处理程序对象之前触发。当事件触发后,页面将由HTTP处理程序处理请求。
void Application_PreRequestHandlerExecute(object sender, EventArgs e) { using (HttpApplication httpApp = (HttpApplication)sender) { Verify(httpApp.Request.Url.AbsolutePath, httpApp.Context, httpApp); } } void Verify(string fileUrl, HttpContext content, HttpApplication httpApp) { if (!String.Equals(httpApp.Request.Url.AbsolutePath, "/Pages/EmployeeNumber.aspx", StringComparison.CurrentCultureIgnoreCase)) { Microsoft.SharePoint.SPWeb contextWeb = Microsoft.SharePoint.WebControls.SPControl.GetContextWeb(content); Microsoft.SharePoint.SPUser user = contextWeb.CurrentUser; if (user != null) { //bool isEmployeeNoExist = true; Microsoft.SharePoint.SPSecurity.RunWithElevatedPrivileges(delegate() { using (Microsoft.SharePoint.SPSite elevatedSite = new Microsoft.SharePoint.SPSite(contextWeb.Site.ID)) { using (Microsoft.SharePoint.SPWeb elevatedWeb = elevatedSite.OpenWeb(contextWeb.ID)) { Microsoft.Office.Server.ServerContext context = Microsoft.Office.Server.ServerContext.GetContext(elevatedSite); Microsoft.Office.Server.UserProfiles.UserProfileManager profileManager = new Microsoft.Office.Server.UserProfiles.UserProfileManager(context); string accountID = user.LoginName; Microsoft.Office.Server.UserProfiles.UserProfile newProfile = profileManager.GetUserProfile(accountID); if (newProfile["EmployeeNo"] == null || newProfile["EmployeeNo"].Value == null || newProfile["EmployeeNo"].Value.ToString() == "") { //isEmployeeNoExist = false; if (IsGroupMember(user, contextWeb, "Internal Members")) { contextWeb = null; httpApp.Response.Redirect("~/Pages/EmployeeNumber.aspx?link=" + httpApp.Server.UrlEncode(httpApp.Request.Url.AbsolutePath)); } else { contextWeb.AllowUnsafeUpdates = true; newProfile["EmployeeNo"].Value = "F0000000"; newProfile.Commit(); contextWeb.AllowUnsafeUpdates = false; contextWeb = null; } } } } }); } } } protected bool IsGroupMember(Microsoft.SharePoint.SPUser spUser, Microsoft.SharePoint.SPWeb spWeb, string operationGroup) { bool isMember = false; try { Microsoft.SharePoint.SPSecurity.RunWithElevatedPrivileges(delegate() { using (Microsoft.SharePoint.SPSite elevatedSite = new Microsoft.SharePoint.SPSite(spWeb.Site.ID)) { using (Microsoft.SharePoint.SPWeb elevatedWeb = elevatedSite.OpenWeb(spWeb.ID)) { Microsoft.SharePoint.SPGroup spGroupOperation = elevatedWeb.SiteGroups[operationGroup]; foreach (Microsoft.SharePoint.SPUser eachUser in spGroupOperation.Users) { if (eachUser.ID == spUser.ID) { isMember = true; break; } } } } }); return isMember; } catch { return isMember; } }
因为用公司内外的用户以及匿名访问,所以添加了一些判定。
结果执行的时候却发现了问题:
1) 可以跳转到对应的页面,但是刷新以后发现页面的样式全部丢失
对Global.asax里的HTTPApplication事件浏览了一下,看的有点晕头转向的,只知道是在身份验证之后,想了下,就选了
Application_PostRequestHandlerExecute : 当HTTP处理程序与页面请求一起完成时触发。此时,Response对象将获得由客
户端返回的数据。 (额,可能是不够严谨吧,后面会仔细研究下的)换成了这个事件以后就没有问题了。
第三步: 填入工号信息并更新"EmployeeNo"
这里代码就很简单了,获取当前的用户的UserProfile,然后对"EmployeeNo"属性赋值,
/// <summary> /// 2010-12-08 Rex Create Update Employee Number for current user /// </summary> /// <param name="sender"></param> /// <param name="e"></param> protected void btnSave_Click(object sender, EventArgs e) { string queryString = this.Page.Request.QueryString.Get("link"); lblError.Text = ""; if (txtEmployeeNo.Text.Trim() == "" || txtEmployeeNo.Text.Trim().ToUpper() == "F0000000" || txtEmployeeNo.Text.Trim().Length > 15) { lblError.Text = "Please input a valid employee number!"; } else { SPWeb contextWeb = SPContext.Current.Web; SPUser user = contextWeb.CurrentUser; SPSecurity.RunWithElevatedPrivileges(delegate() { using (SPSite elevatedSite = new SPSite(contextWeb.Site.ID)) { using (SPWeb elevatedWeb = elevatedSite.OpenWeb(contextWeb.ID)) { Microsoft.Office.Server.ServerContext context = Microsoft.Office.Server.ServerContext.GetContext(elevatedSite); UserProfileManager profileManager = new UserProfileManager(context); string accountID = user.LoginName; UserProfile newProfile = profileManager.GetUserProfile(accountID); newProfile["EmployeeNo"].Value = txtEmployeeNo.Text.Trim().ToUpper(); newProfile.Commit(); if (queryString != null && queryString != "") { this.Page.Response.Redirect("~" + queryString); } else { this.Page.Response.Redirect("~/"); } } } }); } }
结果在执行的时候出错了,经过调试发现时在赋值的时候会报错:
newProfile["EmployeeNo"].Value = txtEmployeeNo.Text.Trim
错误信息: Property not editable
1. 是否是因为属性没有设置正确: 把属性设置为可编辑,还是会报错。、
2. 后来再调试发现还有一句 "You can only edit the property as an administrator",于是想到可能是权限的问题。
一般来说权限的问题用代码权限提升是屡试不爽的,结果这次碰壁了。
上网搜索,结果发现时因为没有管理userprofile的权限, 我发现代码权限提升后对应的账户是"SharePoint/System”,于是想
着把这个账号授予管理UserProfile的权限就可以了吧,结果发现无法添加。 后来的解法是对所有的用户进行授权:
SSP --> "Personalization services permissions" --> 为"NT AUTHORITY/Authenticated Users" 添加/授予 "Manage
UserProfile"的权限。
设置完成后重启应用程序池, 再次执行,成功。