用于在 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, ...')
而不是相等表达式,则有望获得亚秒级响应时间。
先决条件
包含组或用户标识的字段必须是包含“filterable”属性的字符串。 它应该是一个集合。 它不应允许 null。
同一文档中的其他字段应提供该组或用户可访问的内容。 在以下 JSON 文档中,“security_id”字段包含安全筛选器中使用的标识,如果调用方的标识与文档的“security_id”匹配,则该字段包含姓名、工资和婚姻状况。
{ "Employee-1": { "id": "100-1000-10-1-10000-1", "name": "Abram", "salary": 75000, "married": true, "security_id": "10011" }, "Employee-2": { "id": "200-2000-20-2-20000-2", "name": "Adams", "salary": 75000, "married": true, "security_id": "20022" } }
注意
本文不介绍检索主体标识符并将这些字符串注入可由 Azure AI 搜索编制索引的源文档的过程。 有关如何获取标识符,请参阅标识服务提供商的文档。
创建安全字段
在搜索索引的字段集合中,需有一个包含组或用户标识的字段,类似于以上示例中虚构的“security_id”字段。
将一个安全字段添加为
Collection(Edm.String)
。 确保该字段的filterable
属性设置为true
,以便根据用户拥有的访问权限筛选搜索结果。 例如,如果针对file_name
为“secured_file_b”的文档将group_ids
字段设置为["group_id1, group_id2"]
,则只有属于组 ID“group_id1”或“group_id2”的用户才对该文件拥有读访问权限。将该字段的
retrievable
属性设置为false
,这样就不会将其返回为搜索请求的一部分。索引需要文档键。 “file_id”字段符合该要求。 索引还应包含可搜索的内容。 在此示例中,“file_name”和“file_description”字段符合该要求。
POST https://[search service].search.azure.cn/indexes/securedfiles/docs/index?api-version=2023-11-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 将数据推送到索引中
将 HTTP POST 请求发送到索引的 URL 终结点的文档集合(请参阅“文档 - 索引”)。 HTTP 请求的正文是要编制索引的文档的 JSON 呈现:
POST https://[search service].search.azure.cn/indexes/securedfiles/docs/index?api-version=2023-11-01
在请求正文中,指定文档的内容:
{
"value": [
{
"@search.action": "upload",
"file_id": "1",
"file_name": "secured_file_a",
"file_description": "File access is restricted to the 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=2020-06-30
Content-Type: application/json
api-key: [admin or query key]
在请求正文中指定筛选器:
{
"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
函数会筛选出任何用户主体都对其没有读访问权限的搜索结果。 主体标识符可以表示安全组、角色甚至用户自己的标识等信息。
对于基于 Microsoft Entra ID 的替代模式,或者要重新访问其他安全功能,请参阅以下链接。