用于在 Azure AI 搜索中修整结果的安全筛选器
Azure AI 搜索不提供本机文档级权限,也不能根据用户权限改变同一索引中的搜索结果。 一种解决方法是创建一个筛选器,以便根据包含组或用户标识的字符串来修整搜索结果。
本文将介绍一种安全筛选模式,其中包括以下步骤:
- 使用所需内容汇编源文档
- 为主体标识符创建一个字段
- 将文档推送到搜索索引以编制索引
- 使用
search.in
筛选器函数查询索引
文章最后提供了提供实践学习的演示和示例链接。 建议先查看本文以了解模式。
关于安全筛选器模式
尽管 Azure AI 搜索未与用于访问索引中内容的安全子系统集成,但筛选器可以满足许多客户的文档级安全要求。
在 Azure AI 搜索中,安全筛选器是一个常规 OData 筛选器,它根据由安全主体组成的字符串包含或排除搜索结果。 不会通过安全主体进行身份验证或授权。 主体只是在筛选表达式中使用的一个字符串,用于在搜索结果中包含或排除文档。
有多种方法可以实现安全筛选。 一种方法是通过相等表达式进行复杂析取:例如 Id eq 'id1' or Id eq 'id2'
等。 此方法容易出错且难以维护,如果列表包含数百甚至数千个值,会将查询响应时间减慢许多秒。
更好的解决方法是将 search.in
函数用于安全筛选器,如本文中所述。 如果使用 search.in(Id, 'id1, id2, ...')
而不是相等表达式,则有望获得亚秒级响应时间。
先决条件
包含组或用户标识的字符串字段,例如 Microsoft Entra 对象标识符。
同一文档中的其他字段应提供该组或用户可访问的内容。 在以下 JSON 文档中,“security_id”字段包含安全筛选器中使用的标识,如果调用方的标识与文档的“security_id”匹配,则该字段包含姓名、工资和婚姻状况。
{ "Employee-1": { "employee_id": "100-1000-10-1-10000-1", "name": "Abram", "salary": 75000, "married": true, "security_id": "alphanumeric-object-id-for-employee-1" }, "Employee-2": { "employee_id": "200-2000-20-2-20000-2", "name": "Adams", "salary": 75000, "married": true, "security_id": "alphanumeric-object-id-for-employee-2" } }
创建安全字段
在搜索索引的字段集合中,需有一个包含组或用户标识的字段,类似于以上示例中虚构的“security_id”字段。
将一个安全字段添加为
Collection(Edm.String)
。将字段的
filterable
属性设置为true
。将该字段的
retrievable
属性设置为false
,这样就不会将其返回为搜索请求的一部分。索引需要文档键。 “file_id”字段符合该要求。
索引还应包含可搜索和可检索的内容。 在此示例中,“file_name”和“file_description”字段符合该要求。
以下索引架构满足字段要求。 在 Azure AI 搜索上编制索引的文档应具有所有这些字段的值,包括“group_ids”。 对于
file_name
为“secured_file_b”的文档,只有属于组 ID“group_id1”或“group_id2”的用户才对该文件拥有读访问权限。POST https://[search service].search.azure.cn/indexes/securedfiles/docs/index?api-version=2024-07-01 { "name": "securedfiles", "fields": [ {"name": "file_id", "type": "Edm.String", "key": true, "searchable": false }, {"name": "file_name", "type": "Edm.String", "searchable": true }, {"name": "file_description", "type": "Edm.String", "searchable": true }, {"name": "group_ids", "type": "Collection(Edm.String)", "filterable": true, "retrievable": false } ] }
使用 REST API 将数据推送到索引中
使用文档填充搜索索引,这些文档为字段集合中的每个字段提供值,包括安全字段的值。 Azure AI 搜索不提供用于专门填充安全字段的 API 或功能。 然而,本文末尾列出的几个示例解释了填充该字段的技术。
在 Azure AI 搜索中,加载数据的方法包括:
- 导入填充了所有字段的文档的单个推送或拉取(索引器)操作
- 多个推送或拉取操作。 只要辅助导入操作以正确的文档标识符为目标,就可以通过多个导入单独加载字段。
以下示例展示了将单个 HTTP POST 请求发送到索引的 URL 终结点的文档集合(请参阅“文档 - 索引”)。 HTTP 请求的正文是要编制索引的文档的 JSON 呈现:
POST https://[search service].search.azure.cn/indexes/securedfiles/docs/index?api-version=2024-07-01
{
"value": [
{
"@search.action": "upload",
"file_id": "1",
"file_name": "secured_file_a",
"file_description": "File access is restricted to Human Resources.",
"group_ids": ["group_id1"]
},
{
"@search.action": "upload",
"file_id": "2",
"file_name": "secured_file_b",
"file_description": "File access is restricted to Human Resources and Recruiting.",
"group_ids": ["group_id1", "group_id2"]
},
{
"@search.action": "upload",
"file_id": "3",
"file_name": "secured_file_c",
"file_description": "File access is restricted to Operations and Logistics.",
"group_ids": ["group_id5", "group_id6"]
}
]
}
如需使用组列表更新现有文档,可以使用 merge
或 mergeOrUpload
操作:
{
"value": [
{
"@search.action": "mergeOrUpload",
"file_id": "3",
"group_ids": ["group_id7", "group_id8", "group_id9"]
}
]
}
在查询中应用安全筛选器
若要基于 group_ids
访问权限修整文档,应发出包含 group_ids/any(g:search.in(g, 'group_id1, group_id2,...'))
筛选器的搜索查询,其中,'group_id1, group_id2,...' 是搜索请求发出者所属的组。
此筛选器匹配其 group_ids
字段包含某个给定标识符的所有文档。
有关使用 Azure AI 搜索搜索文档的完整详细信息,可以阅读搜索文档。
此示例演示如何使用 POST 请求设置查询。
发出 HTTP POST 请求,并在请求正文中指定筛选器:
POST https://[service name].search.azure.cn/indexes/securedfiles/docs/search?api-version=2024-07-01
{
"filter":"group_ids/any(g:search.in(g, 'group_id1, group_id2'))"
}
应该获取 group_ids
包含“group_id1”或“group_id2”的文档。 换而言之,应获取请求发出者对其拥有读访问权限的文档。
{
[
{
"@search.score":1.0,
"file_id":"1",
"file_name":"secured_file_a",
},
{
"@search.score":1.0,
"file_id":"2",
"file_name":"secured_file_b"
}
]
}
后续步骤
本文介绍了基于用户标识和 search.in()
函数筛选结果的模式。 可以使用此函数传入请求用户的主体标识符,以将其与每个目标文档关联的主体标识符进行匹配。 处理搜索请求时,search.in
函数会筛选出任何用户主体都对其没有读访问权限的搜索结果。 主体标识符可以表示安全组、角色甚至用户自己的标识等信息。
有关更多示例、演示和视频,请参阅以下资源: