使用 Azure Active Directory 对 Azure AI 搜索结果进行剪裁的安全筛选器

本文演示如何将安全标识与 Azure AI 搜索中的筛选器结合使用,以根据用户组成员身份剪裁搜索结果。

本文介绍以下任务:

  • 创建组和用户
  • 将用户与已创建的组相关联
  • 缓存新组
  • 对与组关联的文档进行索引
  • 使用组标识符筛选器发出搜索请求

先决条件

Azure AI 搜索中的索引必须具有安全字段,才能存储对文档具有读取访问权限的组标识列表。 此用例假定安全对象(如个人大学申请)与安全字段之间的一对一对应关系,该字段指定谁有权访问该项目(招生人员)。

必须具有租户管理员权限(所有者或管理员)才能创建用户、组和关联。

您的应用程序还必须注册为多租户应用程序,具体步骤如下所述。

将应用程序注册到 Azure Active Directory

此步骤将应用程序与 Azure Active Directory 集成,以便接受用户和组帐户的登录。 如果你不是组织中的租户管理员,可能需要创建新租户来执行以下步骤。

  1. Azure 门户中,找到 Azure Active Directory 租户。

  2. 在左侧 管理下,选择 应用注册,然后选择 新注册

  3. 为注册起个名字,可以是与搜索应用程序名称相似的名字。 有关其他可选属性的信息,请参阅本文

  4. 选择 注册

  5. 创建应用注册后,复制应用程序(客户端)ID。 需要向应用程序提供此字符串。

    如果要单步执行 DotNetHowToSecurityTrimming,请将此值粘贴到 app.config 文件中。

  6. 复制目录(租户)ID。

  7. 在左侧,选择 API 权限,然后选择 添加权限

  8. 选择 Microsoft Graph,然后选择 委托权限

  9. 搜索并添加以下委派权限:

    • Directory.ReadWrite.All
    • Group.ReadWrite.All
    • User.ReadWrite.All

    Microsoft Graph 提供了一个 API,允许通过 REST API 以编程方式访问 Azure Active Directory。 本演练的代码示例使用权限来调用 Microsoft 图形 API,以创建组、用户和关联。 这些 API 还用于缓存组标识符,以便更快地进行筛选。

  10. 选择 为租户 授予管理员同意以完成同意过程。

创建用户和组

如果要将搜索添加到已建立的应用程序,则可能在 Azure Active Directory 中具有现有的用户和组标识符。 在这种情况下,可以跳过接下来的三个步骤。

但是,如果没有现有用户,可以使用 Microsoft Graph API 来创建安全主体。 以下代码片段演示如何生成标识符,这些标识符将成为 Azure AI 搜索索引中安全字段的数据值。 在我们假设的大学招生申请中,这将是招生人员的安全标识符。

用户和组成员身份可能非常流畅,尤其是在大型组织中。 用于生成用户和组身份的代码应经常运行,以便跟踪组织成员身份的变化。 同样,Azure AI 搜索索引需要类似的更新计划来反映允许的用户和资源的当前状态。

步骤 1:创建组

private static Dictionary<Group, List<User>> CreateGroupsWithUsers(string tenant)
{
    Group group = new Group()
    {
        DisplayName = "My First Prog Group",
        SecurityEnabled = true,
        MailEnabled = false,
        MailNickname = "group1"
    };

步骤 2:创建用户

User user1 = new User()
{
    GivenName = "First User",
    Surname = "User1",
    MailNickname = "User1",
    DisplayName = "First User",
    UserPrincipalName = String.Format("user1@{0}", tenant),
    PasswordProfile = new PasswordProfile() { Password = "********" },
    AccountEnabled = true
};

步骤 3:关联用户和组

List<User> users = new List<User>() { user1, user2 };
Dictionary<Group, List<User>> groups = new Dictionary<Group, List<User>>() { { group, users } };

步骤 4:缓存组标识符

(可选)为了降低网络延迟,可以缓存用户组关联,以便在发出搜索请求时,从缓存返回组,从而节省往返。 可以使用 Batch API 发送包含多个用户的单个 Http 请求并生成缓存。

Microsoft Graph 旨在处理大量请求。 如果出现大量请求,Microsoft Graph 将失败请求并显示 HTTP 状态代码 429。 有关详细信息,请参阅 Microsoft Graph 限制策略

使用允许的组为文档编制索引

Azure AI 搜索中的查询作通过 Azure AI 搜索索引执行。 在此步骤中,索引作将可搜索数据导入索引,包括用作安全筛选器的标识符。

Azure AI 搜索不会对用户标识进行身份验证,也不提供用于确定用户有权查看的内容的逻辑。 安全剪裁的用例假定你提供敏感文档与有权访问该文档的组标识符之间的关联,并完整地导入到搜索索引中。

在假设示例中,Azure AI 搜索索引上的 PUT 请求正文将包括申请人的大学论文或脚本以及有权查看该内容的组标识符。

在本演练的代码示例中使用的泛型示例中,索引操作可能是以下这样:

private static void IndexDocuments(string indexName, List<string> groups)
{
    IndexDocumentsBatch<SecuredFiles> batch = IndexDocumentsBatch.Create(
        IndexDocumentsAction.Upload(
            new SecuredFiles()
            {
                FileId = "1",
                Name = "secured_file_a",
                GroupIds = new[] { groups[0] }
            }),
              ...
            };

IndexDocumentsResult result = searchClient.IndexDocuments(batch);

发出搜索请求

出于安全修整的目的,索引中安全字段中的值是用于在搜索结果中包含或排除文档的静态值。 例如,如果入学的组标识符是“A11B22C33D44-E55F66G77-H88I99JKK”,那么在 Azure AI 搜索索引的安全字段中具有该标识符的任何文档都会被包括在返回给调用者的搜索结果中(或被排除)。

若要根据发出请求的用户组筛选搜索结果中返回的文档,请查看以下步骤。

步骤 1:检索用户的组标识符

如果用户的组尚未缓存,或者缓存已过期,请发出 请求。

private static async void RefreshCache(IEnumerable<User> users)
{
    HttpClient client = new HttpClient();
    var userGroups = await _microsoftGraphHelper.GetGroupsForUsers(client, users);
    _groupsCache = new ConcurrentDictionary<string, List<string>>(userGroups);
}

步骤 2:撰写搜索请求

假设你有用户的组成员身份,则可以使用适当的筛选器值发出搜索请求。

private static void SearchQueryWithFilter(string user)
{
    // Using the filter below, the search result will contain all documents that their GroupIds field   
    // contain any one of the Ids in the groups list
    string filter = String.Format("groupIds/any(p:search.in(p, '{0}'))", string.Join(",", String.Join(",", _groupsCache[user])));
    SearchOptions searchOptions =
        new SearchOptions()
        {
            Filter = filter
        };
    searchOptions.Select.Add("name");

    SearchResults<SecuredFiles> results = searchClient.Search<SecuredFiles>("*", searchOptions);

    Console.WriteLine("Results for groups '{0}' : {1}", _groupsCache[user], results.GetResults().Select(r => r.Document.Name));
}

步骤 3:处理结果

响应包括筛选的文档列表,其中包括用户有权查看的文档。 根据构造搜索结果页面的方式,可能需要包含视觉提示以反映筛选的结果集。

外卖

在本演练中,你了解了使用用户登录筛选 Azure AI 搜索结果中的文档的模式,并剪裁了与请求上提供的筛选器不匹配的文档的结果。