对 SharePoint Server 搜索结果使用自定义 Security Trimmer
此操作说明逐步介绍了如何使用 Microsoft Visual Studio 2010 对 SharePoint 中的搜索功能实现(即创建、部署和注册)自定义 Security Trimmer。
SharePoint 中的搜索功能对搜索结果执行查询时安全修整。 不过,有时可能需要执行自定义安全修整。 SharePoint 中的搜索通过 Microsoft.Office.Server.搜索为这些方案提供支持。Query.ISecurityTrimmerPre ,Microsoft.Office.Server.搜索。Query.ISecurityTrimmerPost 和 ISecurityTrimmer2 (Microsoft.Office.Server.搜索中弃用的) 接口。查询命名空间。
自定义安全修整有两种类型:前期修整和后期修整。 前期修整是指查询前评估,即在将查询与搜索索引匹配之前先重写该查询以添加安全信息。 后期修整是指查询后评估,即在将搜索结果返回给用户之前先对搜索结果进行修剪。 我们建议使用前期修整提高性能和进行一般更正;使用后期修整防止精简程序数据和命中次数实例的信息泄漏。
利用安全修整程序注册过程,可以指定自定义安全修整程序的配置属性。
概述
SharePoint 中的搜索功能中的自定义安全修整包含两个接口,可用于对搜索结果执行前期修整或后期修整。 本操作方法重点介绍这两个接口,描述创建和注册您自己的安全修整程序所需的步骤。
先决条件
若要完成本操作方法,必须在开发环境中安装以下各项:
- Microsoft SharePoint 中的搜索功能
- Microsoft Visual Studio 2010 或类似的与 Microsoft .NET Framework 兼容的开发工具
设置自定义安全修整程序项目
在此步骤中,您将创建自定义安全修整程序项目,然后添加对该项目的必需引用。
创建用于自定义安全修整程序的项目
- 打开 Visual Studio,依次选择"文件"、"新建"、"项目"。
- 在"项目类型"中的"C#"下,选择"SharePoint"。
- 在"模板"下,选择"空白 SharePoint 项目"。 在"名称"字段中,键入"CustomSecurityTrimmerSample",然后选择"确定"按钮。
- 在"SharePoint 自定义向导"中,选择"部署为场解决方案",然后选择"完成"。
添加对自定义安全修整程序项目的引用
在"项目"菜单上,选择"添加引用"。
在".NET"选项卡上,选择具有以下组件名称的引用,然后选择"确定"按钮:
- Microsoft 搜索组件
应该会在“.NET”选项卡上看到两个组件名称为“Microsoft 搜索组件”的条目。 选择要在其中 \ISAPI\Microsoft.Office.Server.Search.dll“路径”列的条目。 如果“添加引用”对话框中的“.NET”选项卡上没有此条目,必须使用 Microsoft.Office.Server.Search.dll 的路径,在“浏览”选项卡中添加引用。
- Microsoft.IdentityModel
如果"Microsoft.IdentityModel"未在".NET"选项卡上列出,则必须使用以下路径从"浏览"选项卡添加对 Microsoft.IdentityModel.dll 的引用:
%ProgramFiles%\\Reference Assemblies\\Microsoft\\Windows Identity Foundation\\v4.0.
创建自定义前期安全修整程序
为前期安全修整程序创建类文件
- 在"项目"菜单上,选择"添加新项"。
- 在"已安装的模板"中的"Visual C# 项"下方,选择"代码",然后选择"类"。
- 键入"CustomSecurityPreTrimmer.cs",然后选择"添加"。
编写自定义前期安全修整程序代码
您的自定义安全修整程序必须实现 ISecurityTrimmerPre 接口。 以下代码示例是此接口的基本实现。
修改 CustomSecurityPreTrimmer 中的默认代码
在类的开头添加以下 using 指令。
using System; using System.Collections; using System.Collections.Generic; using System.Collections.Specialized; using System.Security.Principal; using Microsoft.IdentityModel.Claims; using Microsoft.Office.Server.Search.Query; using Microsoft.Office.Server.Search.Administration;
在类声明中指定 CustomSecurityPreTrimmer 类实现 ISecurityTrimmerPre 接口,如以下代码所示。
public class CustomSecurityPreTrimmer : ISecurityTrimmerPre
实现 ISecurityTrimmerPre 接口方法
为 Initialize () 方法声明添加以下代码。
public void Initialize(NameValueCollection staticProperties, SearchServiceApplication searchApplication) { }
该示例的基本版本未在 Initialize 方法中包含任何代码。
为 AddAccess () 方法声明添加以下代码。
public IEnumerable<Tuple<Claim, bool>> AddAccess( IDictionary<string, object> sessionProperties, IIdentity passedUserIdentity) { //AddAccess method implementation, see steps 3-5. }
在 AddAccess 方法实现的第一部分中,我们通过查看 passedUserIdentity 查明用户身份。
if (passedUserIdentity == null) { throw new ArgumentException("AddAccess method is called with invalid user identity parameter", "passedUserIdentity"); } String strUser = null; var claimsIdentity = (IClaimsIdentity)passedUserIdentity; if (claimsIdentity != null) { foreach (var claim in claimsIdentity.Claims) { if (claim == null) { continue; } // strUser is "domain\\\\user" format when web app is in Claims Windows Mode if (SPClaimTypes.Equals(claim.ClaimType, SPClaimTypes.UserLogonName)) { strUser = claim.Value; break; } // strUser2 is "S-1-5-21-2127521184-1604012920-1887927527-66602" when web app is in Legacy Windows Mode // In this case we need to convert it into NT user format. if (SPClaimTypes.Equals(claim.ClaimType, ClaimTypes.PrimarySid)) { strUser = claim.Value; SecurityIdentifier sid = new SecurityIdentifier(strUser); strUser = sid.Translate(typeof(NTAccount)).Value; break; } } }
创建列表,使用声明填充该列表并返回该列表,如以下代码所示。
var claims = new LinkedList<Tuple<Claim, bool>>(); if (!string.IsNullOrEmpty(strUser)) { var groupMembership = GetMembership(strUser); if (!string.IsNullOrEmpty(groupMembership)) { var groups = groupMembership.Split(new[] {';'}, StringSplitOptions.RemoveEmptyEntries); foreach (var group in groups) { claims.AddLast(new Tuple<Claim, bool>( new Claim("http://schemas.happy.bdc.microsoft.com/claims/acl", group), false)); } } } return claims; }
GetMembership 方法包含修整程序的自定义逻辑。
创建自定义后期安全修整程序
为后期安全修整程序创建类文件
- 在"项目"菜单上,选择"添加新项"。
- 在"已安装的模板"中的"Visual C# 项"下方,选择"代码",然后选择"类"。
- 键入"CustomSecurityPostTrimmer.cs",然后选择"添加"。
编写自定义后期安全修整程序代码
您的自定义安全修整程序必须实现 ISecurityTrimmerPost 接口。 本节中的代码示例是此接口的基本实现。
修改 CustomSecurityPostTrimmer 中的默认代码
在类的开头添加以下 using 指令:
using System; using System.Collections; using System.Collections.Generic; using System.Collections.Specialized; using System.Security.Principal; using Microsoft.IdentityModel.Claims; using Microsoft.Office.Server.Search.Query; using Microsoft.Office.Server.Search.Administration;
在类声明中指定 CustomSecurityPostTrimmer 类实现 ISecurityTrimmerPost 接口,如下所示:
public class CustomSecurityPostTrimmer : ISecurityTrimmerPost
实现 ISecurityTrimmerPost 接口方法
为 Initialize () 方法声明添加以下代码。
public void Initialize(NameValueCollection staticProperties, SearchServiceApplication searchApplication) { }
该示例的基本版本未在 Initialize 方法中包含任何代码。
为 CheckAccess () 方法声明添加以下代码。
public BitArray CheckAccess(IList<string> documentCrawlUrls, IList<string> documentAcls, IDictionary<string, object> sessionProperties, IIdentity passedUserIdentity) { //CheckAccess method implementation, see steps 3-5. }
在 CheckAccess 方法实现的第一部分中,声明并初始化 BitArray 变量以便在 documentCrawlUrls 集合中存储每个 URL 的访问检查结果,并检索提交该查询的用户,如以下代码所示。
if (documentCrawlUrls == null) { throw new ArgumentException("CheckAccess method is called with invalid URL list", "documentCrawlUrls"); } if (documentAcls == null) { throw new ArgumentException("CheckAccess method is called with invalid documentAcls list", "documentAcls"); } if (passedUserIdentity == null) { throw new ArgumentException("CheckAccess method is called with invalid user identity parameter", "passedUserIdentity"); }
循环集合中的每个爬网 URL 并执行访问检查,以确定提交查询的用户是否可以访问爬网 URL 的相关内容项,如以下代码所示。
// Initialize the bit array with TRUE value which means all results are visible by default. var urlStatusArray = new BitArray(documentCrawlUrls.Count, true); var claimsIdentity = (IClaimsIdentity)passedUserIdentity; if (claimsIdentity != null) { var userGroups = GetGroupList(claimsIdentity.Claims); var numberDocs = documentCrawlUrls.Count; for (var i = 0; i < numberDocs; ++i) { if (!string.IsNullOrEmpty(documentAcls[i])) { urlStatusArray[i] = VerifyAccess(documentAcls[i], userGroups); } } }
如果用户具有访问该内容项的权限,请将位于该索引 ( urlStatusArray[i]) 的 BitArray 项的值设为 true;否则,将其设为 false。
将 CheckAccess 方法的返回值设置为 urlStatusArray,如下面的代码所示。
return urlStatusArray;
注册自定义安全修整程序
此步骤介绍如何配置自定义安全修整程序,并包括以下任务:
- 使用 Windows PowerShell cmdlet 为搜索服务应用程序注册自定义安全修整程序。
- 注册 SharePoint 搜索主机控制器 (SPSearchHostController)。
注册自定义安全修整程序
使用 SharePoint 命令行管理程序向 ClassName 注册自定义安全修整程序。 在本例中, ClassName 可以是 CustomSecurityPreTrimmer 或 CustomSecurityPostTrimmer。 以下过程将演示如何注册自定义安全修整程序,并将搜索服务应用程序的 ID 设置为 1。
注册自定义安全修整程序
在 Windows 资源管理器中,在路径 <Local_Drive:\WINDOWS\assembly 中找到 CustomSecurityTrimmerSample.dll>。
打开文件的快捷菜单,然后选择"属性"。
在"属性"对话框中的"常规"选项卡上,选择并复制标记。
打开 SharePoint 命令行管理程序。 有关使用此工具的信息,请参阅 使用 SharePoint 2010 命令行管理程序管理服务应用程序
在命令提示符处,键入以下命令。
New-SPEnterpriseSearchSecurityTrimmer -SearchApplication "Search Service Application" -typeName "CustomSecurityTrimmerSample.ClassName, CustomSecurityTrimmerSample, Version=1.0.0.0, Culture=neutral, PublicKeyToken=token" -RulePath "xmldoc://*"
在 命令中,将 ClassName 替换为 CustomSecurityPreTrimmer 或 CustomSecurityPostTrimmer ,并将 token 替换为 CustomSecurityTrimmerSample.dll 文件的公钥令牌。 您必须将所有后修整程序与 "xmldoc://*" 爬网规则关联,但此操作是预修整程序的可选操作。
注意
如果您有多个前端 Web 服务器,则必须将安全修整程序部署到服务器场中所有前端 Web 服务器上的全局程序集缓存。
确认您的安全修整程序是使用以下 PowerShell cmdlet 注册的。
$searchApp = Get-SPEnterpriseSearchServiceApplication $searchApp | Get-SPEnterpriseSearchSecurityTrimmer
安全修整程序在结果中必须是可见的。
重启 SharePoint 搜索主机控制器
您可以键入下列 PowerShell cmdlet 来重启搜索服务
net restart sphostcontrollerservice