Partager via


Filtres de sécurité pour le filtrage des résultats dans la recherche Azure AI

Recherche Azure AI ne fournit pas d’autorisations natives au niveau du document et ne peut pas faire varier les résultats de la recherche au sein du même index selon les autorisations de l’utilisateur. Pour contourner ce problème, vous pouvez créer un filtre qui répartit les résultats de la recherche en fonction d’une chaîne contenant une identité de groupe ou d’utilisateur.

Cet article décrit un modèle de filtrage de sécurité qui comprend les étapes suivantes :

  • Assembler des documents sources avec le contenu requis
  • Créer un champ pour les identificateurs de principal
  • Envoyer (push) les documents à l’index de recherche pour l’indexation
  • Interroger l’index avec la fonction de filtre search.in

Il se termine par des liens vers des démonstrations et des exemples qui permettent un apprentissage par la pratique. Nous vous recommandons de commencer par examiner cet article pour comprendre le modèle.

À propos du modèle de filtre de sécurité

Bien que Recherche Azure AI ne s’intègre pas aux sous-systèmes de sécurité pour accéder au contenu d’un index, de nombreux clients qui ont des exigences de sécurité au niveau du document constatent que les filtres peuvent répondre à leurs besoins.

Dans Recherche Azure AI, un filtre de sécurité est un filtre OData standard qui inclut ou exclut un résultat de la recherche en fonction d’une chaîne consistant en un principal de sécurité. Il n’existe aucune authentification ou autorisation par le biais du principal de sécurité. Le principal est simplement une chaîne, utilisée dans une expression de filtre, pour inclure ou exclure un document des résultats de la recherche.

Il existe plusieurs façons de mettre en place le filtrage de sécurité. Une méthode consiste à utiliser une disjonction complexe d’expressions d’égalité. Par exemple : Id eq 'id1' or Id eq 'id2', etc. Cette approche est sujette aux erreurs et difficile à gérer. De plus, si la liste contient des centaines voire des milliers de valeurs, elle ralentit le temps de réponse de plusieurs secondes.

Une meilleure solution consiste à utiliser la fonction search.in pour les filtres de sécurité, comme décrit dans cet article. En utilisant search.in(Id, 'id1, id2, ...') à la place d’une expression d’égalité, vous pouvez obtenir des temps de réponse inférieurs à une seconde.

Prérequis

  • Un champ de type chaîne contenant une identité de groupe ou d’utilisateur, comme un identificateur d’objet Microsoft Entra.

  • Les autres champs du même document doivent fournir le contenu accessible à ce groupe ou à cet utilisateur. Dans les documents JSON suivants, les champs « security_id » contiennent des identités utilisées dans un filtre de sécurité, et le nom, le salaire et l’état civil sont inclus si l’identité de l’appelant correspond au « security_id » du document.

    {  
        "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"
        } 
    }  
    

Créer le champ de sécurité

Dans l’index de recherche, dans la collection de champs, vous avez besoin d’un champ qui contient l’identité du groupe ou de l’utilisateur, similaire au champ fictif « security_id » de l’exemple précédent.

  1. Ajoutez un champ de sécurité en tant que Collection(Edm.String).

  2. Définissez l’attribut filterable du champ sur true.

  3. Définissez l’attribut retrievable du champ sur false pour qu’il ne soit pas retourné dans le cadre de la requête de recherche.

  4. Les index nécessitent une clé de document. Le champ « file_id » répond à cette exigence.

  5. Les index doivent également contenir du contenu pouvant faire l’objet d’une recherche et d’une extraction. Les champs « file_name » et « file_description » représentent cela dans cet exemple.

    Le schéma d’index suivant répond aux exigences en matière de champs. Les documents que vous indexez sur Recherche Azure AI doivent avoir des valeurs pour tous ces champs, y compris « group_ids ». Pour le document avec file_name « secured_file_b », seuls les utilisateurs qui appartiennent aux ID de groupe « group_id1 » ou « group_id2 » ont accès en lecture au fichier.

    POST https://[search service].search.windows.net/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 }
         ]
     }
    

Envoi (push) des données à votre index à l’aide de l’API REST

Alimentez votre index de recherche avec des documents qui fournissent des valeurs pour chaque champ de la collection de champs, y compris des valeurs pour le champ de sécurité. Recherche Azure AI ne fournit pas d’API ni de fonctionnalités pour renseigner spécifiquement le champ de sécurité. Cependant, plusieurs exemples listés à la fin de cet article expliquent des techniques pour renseigne ce champ.

Dans Recherche Azure AI, les approches pour charger des données sont les suivantes :

  • Une seule opération d’envoi (push) ou d’extraction (indexeur) qui importe des documents avec tous les champs renseignés.
  • Plusieurs opérations d’envoi (push) ou d’extraction. Dès lors que les opérations d’importation secondaire ciblent l’identificateur de document approprié, vous pouvez charger des champs individuellement via plusieurs importations.

L’exemple suivant montre une seule requête HTTP POST sur la collection de documents du point de terminaison d’URL de votre index (voir Documents – Index). Le corps de la requête HTTP est un rendu JSON des documents à indexer :

POST https://[search service].search.windows.net/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 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"]
        }
    ]
}

Si vous avez besoin de mettre à jour un document existant avec la liste des groupes, vous pouvez utiliser l’action merge ou mergeOrUpload :

{
    "value": [
        {
            "@search.action": "mergeOrUpload",
            "file_id": "3",
            "group_ids": ["group_id7", "group_id8", "group_id9"]
        }
    ]
}

Appliquer le filtre de sécurité sur la requête

Pour filtrer des documents en fonction de l’accès de group_ids, vous devez émettre une requête de recherche avec un filtre group_ids/any(g:search.in(g, 'group_id1, group_id2,...')), où « group_id1, group_id2,... » sont les groupes auxquels l’émetteur de la requête de recherche appartient.

Ce filtre correspond à tous les documents dont le champ group_ids contient l’un des identificateurs donnés. Pour obtenir des informations détaillées sur la recherche de documents à l’aide de la recherche Azure AI, lisez Recherche dans des documents.

Cet exemple montre comment configurer une requête à l’aide d’une requête POST.

Émettez la requête HTTP POST en spécifiant le filtre dans le corps de la requête :

POST https://[service name].search.windows.net/indexes/securedfiles/docs/search?api-version=2023-11-01

{
   "filter":"group_ids/any(g:search.in(g, 'group_id1, group_id2'))"  
}

Vous devez obtenir les documents où group_ids contient « group_id1 » ou « group_id2 ». En d’autres termes, vous obtenez les documents auxquels l’émetteur de la requête a accès en lecture.

{
 [
   {
    "@search.score":1.0,
     "file_id":"1",
     "file_name":"secured_file_a",
   },
   {
     "@search.score":1.0,
     "file_id":"2",
     "file_name":"secured_file_b"
   }
 ]
}

Étapes suivantes

Cet article a décrit un modèle de filtrage des résultats en fonction de l’identité utilisateur et de la fonction search.in(). Vous pouvez utiliser cette fonction pour passer les identificateurs de principal de l’utilisateur demandeur et les mettre en correspondance avec les identificateurs de principal associés à chaque document cible. Quand une requête de recherche est traitée, la fonction search.in exclut les résultats de la recherche inaccessibles en lecture aux principaux de l’utilisateur. Les identificateurs de principal peuvent représenter des groupes de sécurité, des rôles ou même la propre identité de l’utilisateur.

Pour obtenir d’autres exemples, démonstrations et vidéos :