UserProfile创建时拒绝访问?
这两天在做一个POC,组织结构的同步。做了一个通用框架,为了做示例和测试,写了一个到用户配置文件(UserProfile)和组织结构配置文件(OrganizationProfile)的接口,然后通过事件处理程序来调用UserProfile的相关接口,把信息同步到用户配置文件中。
然后就出现了问题:在通过事件处理程序调用UserProfileManager的CreateUserProfile方法时,SharePoint抛出了一个拒绝访问的异常:只有管理员和和本人才能创建用户配置文件云云……可是我执行的账号本来就是系统账号啊,我还又去User Profile Service那边查了一下,有完全控制的管理员权限啊……
然后经过一番搜索,发现关键问题的所在:
UserProfileManager在创建的时候,是依赖HttpContext(不是SPContext)的,而事件处理程序中是没有HttpContext的(即使在w3wp进程中运行也没有,SPContext也没有)。(但是为什么用Console程序写UserProfile程序的时候,也没有HttpContext,就能执行成功呢……不解)
临时岔开一下,而且由于是依赖HttpContext而不是SPContext,在提升权限的时候也会出一些问题,网上有人是重新构造了HttpContext作为创建SPServiceContext的参数,然后再去创建UserProfileManager。期间还用到了反射的方法修改WindowsIdentity的某个非公开属性……
上述方法太麻烦,于是我决定绕路,写一个Web Service扔到layouts里,这样就有HttpContext的上下文信息了。然后在事件处理程序中调用Web Service,并使用DefaultCredential(嗯,在我的场景中,只有管理员有权限去管理这个组织结构,所以直接传递当前身份,也不需要做权限提升)。看起来一切正常了……
BUT!人生最厉害的就是这个BUT!(好吧,这句话是九把刀说的)
当我去调用RemoveUserProfile,妄图去删除一个用户配置文件的时候,再次爆发了拒绝访问的异常(同样的代码Console还是正常,无语)。然后搜索了一下,发现msdn论坛上的一个帖子中描述了类似的问题,不过是在2007中的,本着试试看的方式按照如下方法尝试了一下(2007中的ServerContext被废弃,换成了SPServiceContext):
1: SPSecurity.RunWithElevatedPriviliges(delegate(){
2: HttpContext oldCtx = HttpContext.Current;
3: SPServiceContext sc = SPServiceContext.GetContext(oldCtx);
4: HttpContext.Current = null; // 亮点在这里
5: UserProfileManager upm = new UserProfileManager(sc);
6: upm.RemoveUserProfile("domain\\user");
7: HttpContext.Current = oldCtx; // 还原回来
8: });
于是乎就可耻的成功了……我表示很费解,也很无语……