将应用服务向矢量数据库进行身份验证和授权
本文演示如何管理应用服务 .NET 应用程序与矢量数据库解决方案之间的连接。 其中介绍了如何对受支持的服务使用 Microsoft Entra 托管标识,以及如何安全地为其他服务存储连接字符串。
通过在应用程序中添加矢量数据库,可以为 AI 启用 [语义记忆或矢量存储](矢量存储)。 借助适用于 .NET 的 语义内核 SDK,可以使用你的首选矢量数据库解决方案轻松实现记忆存储和回忆。
先决条件
- 具有活动订阅的 Azure 帐户。 免费创建帐户。
- .NET SDK
Microsoft.SemanticKernel
NuGet 包Microsoft.SemanticKernel.Plugins.Memory
NuGet 包- 创建 .NET 应用程序并将其部署到应用服务
- 创建和部署矢量数据库解决方案
使用 Microsoft Entra 托管标识进行身份验证
如果某个矢量数据库服务支持 Microsoft Entra 身份验证,则可以将托管标识与应用服务配合使用来安全地访问矢量数据库,而无需手动预配或轮换任何机密。 有关支持 Microsoft Entra 身份验证的 Azure 服务列表,请参阅支持 Microsoft Entra 身份验证的 Azure 服务。
将托管标识添加到应用服务
你的应用程序可以被授予两种类型的标识:
- 系统分配的标识与你的应用程序相绑定,如果删除应用,标识也会被删除。 一个应用只能有一个系统分配的标识。
- 用户分配的标识是可以分配给应用的独立 Azure 资源。 一个应用可以具有多个用户分配的标识。
添加系统分配的标识
- 导航到 Azure 门户中的应用页面,然后向下滚动到“设置”组。
- 选择“标识”。
- 在“系统分配”选项卡上,将“状态”切换为“开”,然后选择“保存”。
运行 az webapp identity assign
命令以创建系统分配标识:
az webapp identity assign --name <appName> --resource-group <groupName>
添加用户分配的标识
若要将用户分配的标识添加到应用,请创建该标识,然后将其资源标识符添加到应用配置。
按照这些说明创建用户分配的托管标识资源。
在应用页面的左侧导航窗格中,向下滚动到“设置”组。
选择“标识”。
选择“用户分配的>添加”。
找到之前创建的标识,将其选中,然后选择“添加”。
重要
选择“添加”后,应用将重启。
创建用户分配的标识:
az identity create --resource-group <groupName> --name <identityName>
将标识分配给应用:
az webapp identity assign --resource-group <groupName> --name <appName> --identities <identityId>
将 Azure 角色添加到托管标识
- 在 Azure 门户中,导航到要将矢量数据库访问权限授予到的范围。 该范围可以是“管理组”、“订阅”、“资源组”或特定的 Azure 资源。
- 在左侧导航窗格中,选择“访问控制(IAM)”。
- 依次选择“+ 添加”和“添加角色分配” 。
- 在“角色”选项卡上,选择用于授予对矢量数据库的读取访问权限的适当角色。
- 在“成员”选项卡上,选择托管标识。
- 在“查看 + 分配”选项卡上,选择“查看 + 分配”,以分配角色 。
资源范围
az role assignment create --assignee "<managedIdentityObjectID>" \
--role "<myVectorDbReaderRole>" \
--scope "/subscriptions/<subscriptionId>/resourcegroups/<resourceGroupName>/providers/<providerName>/<resourceType>/<resourceSubType>/<resourceName>"
资源组范围
az role assignment create --assignee "<managedIdentityObjectID>" \
--role "<myVectorDbReaderRole>" \
--scope "/subscriptions/<subscriptionId>/resourcegroups/<resourceGroupName>"
订阅范围
az role assignment create --assignee "<managedIdentityObjectID>" \
--role "<myVectorDbReaderRole>" \
--scope "/subscriptions/<subscriptionId>"
管理组范围
az role assignment create --assignee "<managedIdentityObjectID>" \
--role "<myVectorDbReaderRole>" \
--scope "/providers/Microsoft.Management/managementGroups/<managementGroupName>"
使用矢量数据库实现基于令牌的身份验证
以下代码示例需要这些附加库:
初始化
DefaultAzureCredential
对象以获取应用的托管标识:// Initialize a DefaultAzureCredential. // This credential type will try several authentication flows in order until one is available. // Will pickup Visual Studio or Azure CLI credentials in local environments. // Will pickup managed identity credentials in production deployments. TokenCredential credentials = new DefaultAzureCredential( new DefaultAzureCredentialOptions { // If using a user-assigned identity specify either: // ManagedIdentityClientId or ManagedIdentityResourceId. // e.g.: ManagedIdentityClientId = "myIdentityClientId". } );
为矢量数据库初始化一个
IMemoryStore
对象,然后使用它生成ISemanticTextMemory
:// Retrieve the endpoint obtained from the Azure AI Search deployment. // Retrieve the endpoint and deployments obtained from the Azure OpenAI deployment. // Must use the deployment name not the underlying model name. IConfigurationRoot config = new ConfigurationBuilder().AddUserSecrets<Program>().Build(); string searchEndpoint = config["AZURE_AISEARCH_ENDPOINT"]!; string openAiEndpoint = config["AZURE_OPENAI_ENDPOINT"]!; string embeddingModel = config["AZURE_OPENAI_EMBEDDING_NAME"]!; // The Semantic Kernel SDK provides a connector extension for Azure AI Search. // Initialize an AzureAISearchMemoryStore using your managed identity credentials. IMemoryStore memoryStore = new AzureAISearchMemoryStore(searchEndpoint, credentials); // Build a SemanticMemoryStore with Azure AI Search as the store. // Must also include a text embedding generation service. ISemanticTextMemory memory = new MemoryBuilder() .WithOpenAITextEmbeddingGeneration(embeddingModel, openAiEndpoint) .WithMemoryStore(memoryStore) .Build();
生成
Kernel
对象,然后使用TextMemoryPlugin
导入ISemanticTextMemory
对象:// Build a Kernel, include a chat completion service. string chatModel = config["AZURE_OPENAI_GPT_NAME"]!; Kernel kernel = Kernel .CreateBuilder() .AddAzureOpenAIChatCompletion(chatModel, openAiEndpoint, credentials) .Build(); // Import the semantic memory store as a TextMemoryPlugin. // The TextMemoryPlugin enable recall via prompt expressions. kernel.ImportPluginFromObject(new TextMemoryPlugin(memory));
使用
Kernel
对象调用一个包含记忆回忆的提示:// Must configure the memory collection, number of memories to recall, and relevance score. // The {{...}} syntax represents an expression to Semantic Kernel. // For more information on this syntax see: // https://learn.microsoft.com/semantic-kernel/prompts/prompt-template-syntax string memoryCollection = config["AZURE_OPENAI_MEMORY_NAME"]!; string? result = await kernel.InvokePromptAsync<string>( "{{recall 'where did I grow up?'}}", new() { [TextMemoryPlugin.CollectionParam] = memoryCollection, [TextMemoryPlugin.LimitParam] = "2", [TextMemoryPlugin.RelevanceParam] = "0.79", } ); Console.WriteLine($"Output: {result}");
使用 Key Vault 存储连接机密
如果某个矢量数据库不支持 Microsoft Entra 身份验证,则可以使用 Key Vault 来存储连接机密,并使用应用服务应用程序检索它们。 通过使用 Key Vault 来存储连接机密,可以与多个应用程序共享这些机密,并控制每个应用程序对单个机密的访问。
在执行这些步骤之前,请检索矢量数据库的连接字符串。 例如,请参阅将 Azure Cache for Redis 与 ASP.NET Core Web 应用配合使用。
将连接字符串添加到 Key Vault
重要
在执行这些步骤之前,请确保已使用 Azure 门户创建 Key Vault。
- 在 Azure 门户中导航到你的密钥保管库。
- 在 Key Vault 左侧导航中,依次选择“对象”和“机密”。
- 选择“+ 生成/导入”。
- 在“创建机密”屏幕上,选择以下值:
- 上传选项:
Manual
。 - 名称:键入机密的名称。 机密名称在 Key Vault 中必须是唯一的。
- 值:矢量数据库的连接字符串。
- 让其他值保留默认设置。 选择创建。
- 上传选项:
- 当收到表明机密已成功创建的消息时,就可以在应用程序中使用它了。
重要
在执行这些步骤之前,请确保已使用 Azure CLI 创建 Key Vault。
通过基于角色的访问控制 (RBAC) 向用户帐户授予对密钥保管库的权限,使用 Azure CLI 命令
az role assignment create
分配角色:az role assignment create \ --role "Key Vault Secrets User" \ --assignee "<yourEmailAddress>" \ --scope "/subscriptions/<subscriptionId>/resourceGroups/<resourceGroupName>/providers/Microsoft.KeyVault/vaults/<keyVaultName>"
使用 Azure CLI 命令
az keyvault secret set
将连接字符串添加到 Key Vault:az keyvault secret set \ --vault-name "<keyVaultName>" \ --name "<secretName>" \ --value "<connectionString>"
授予应用服务对 Key Vault 的访问权限
从 Key Vault 实现连接字符串检索
若要使用以下代码示例,需要以下附加库:
Azure.Identity
NuGet 包Azure.Extensions.AspNetCore.Configuration.Secrets
NuGet 包Microsoft.Extensions.Configuration
NuGet 包
这些代码示例使用 Redis 数据库,但你可以将其应用于支持连接字符串的任何矢量数据库。
初始化
DefaultAzureCredential
对象以获取应用的托管标识:// Initialize a DefaultAzureCredential. // This credential type will try several authentication flows in order until one is available. // Will pickup Visual Studio or Azure CLI credentials in local environments. // Will pickup managed identity credentials in production deployments. TokenCredential credentials = new DefaultAzureCredential( new DefaultAzureCredentialOptions { // If using a user-assigned identity specify either: // ManagedIdentityClientId or ManagedIdentityResourceId. // e.g.: ManagedIdentityClientId = "myIdentityClientId". } );
在生成配置时添加 Key Vault,这会将 Key Vault 机密映射到
IConfigurationRoot
对象:// User secrets let you provide connection strings when testing locally // For more info see: https://learn.microsoft.com/aspnet/core/security/app-secrets IConfigurationRoot config = new ConfigurationBuilder() .AddUserSecrets<Program>() .AddAzureKeyVault(new Uri("{vaultURI}"), credentials) .Build(); // Retrieve the Redis connection string obtained from the Key Vault. string redisConnectionString = config["AZURE_REDIS_CONNECT_STRING"]!;
使用 Key Vault 中的矢量数据库连接字符串初始化
IMemoryStore
对象,然后使用该对象生成ISemanticTextMemory
:// Use the connection string to connect to the database IDatabase database = ( await ConnectionMultiplexer.ConnectAsync(redisConnectionString) ).GetDatabase(); // The Semantic Kernel SDK provides a connector extension for Redis. // Initialize an RedisMemoryStore using your managed identity credentials. IMemoryStore memoryStore = new RedisMemoryStore(database); // Retrieve the endpoint and deployments obtained from the Azure OpenAI deployment. // Must use the deployment name not the underlying model name. string openAiEndpoint = config["AZURE_OPENAI_ENDPOINT"]!; string embeddingModel = config["AZURE_OPENAI_EMBEDDING_NAME"]!; // Build a SemanticMemoryStore with Azure AI Search as the store. // Must also include a text embedding generation service. ISemanticTextMemory memory = new MemoryBuilder() .WithOpenAITextEmbeddingGeneration(embeddingModel, openAiEndpoint) .WithMemoryStore(memoryStore) .Build();
生成
Kernel
对象,然后使用TextMemoryPlugin
导入ISemanticTextMemory
对象:// Build a Kernel, include a chat completion service. string chatModel = config["AZURE_OPENAI_GPT_NAME"]!; Kernel kernel = Kernel .CreateBuilder() .AddAzureOpenAIChatCompletion(chatModel, openAiEndpoint, credentials) .Build(); // Import the semantic memory store as a TextMemoryPlugin. // The TextMemoryPlugin enable recall via prompt expressions. kernel.ImportPluginFromObject(new TextMemoryPlugin(memory));
使用
Kernel
对象调用一个包含记忆回忆的提示:// Must configure the memory collection, number of memories to recall, and relevance score. // The {{...}} syntax represents an expression to Semantic Kernel. // For more information on this syntax see: // https://learn.microsoft.com/semantic-kernel/prompts/prompt-template-syntax string memoryCollection = config["AZURE_OPENAI_MEMORY_NAME"]!; string? result = await kernel.InvokePromptAsync<string>( "{{recall 'where did I grow up?'}}", new() { [TextMemoryPlugin.CollectionParam] = memoryCollection, [TextMemoryPlugin.LimitParam] = "2", [TextMemoryPlugin.RelevanceParam] = "0.79", } ); Console.WriteLine($"Output: {result}");
使用应用程序设置存储连接机密
如果某个矢量数据库不支持 Microsoft Entra 身份验证,则可以使用应用服务应用程序设置来存储连接机密。 通过使用应用程序设置,可以存储连接机密,而无需预配任何其他 Azure 资源。
在执行这些步骤之前,请检索矢量数据库的连接字符串。 例如,请参阅在 .NET Framework 中使用 Azure Cache for Redis。
将连接字符串添加到应用程序设置
- 在 Azure 门户中导航到你的应用的页面。
- 在应用的左侧菜单中,选择“配置”>“应用程序设置”。
- 默认情况下,为了安全起见,应用程序设置的值隐藏在门户中。
- 若要查看应用程序设置的隐藏值,请选择其“值”字段。
- 选择“新建连接设置”。
- 在“添加/编辑连接字符串”屏幕上,选择以下值:
- 名称:为该设置键入一个名称。 设置名称必须唯一。
- 值:矢量数据库的连接字符串。
- 类型:连接的类型,如果没有任何其他值适用,则为
Custom
。 - 让其他值保留默认设置。 选择“确定”。
- 在“配置”页中选择“保存”。
使用 Azure CLI 命令 az webapp config connection-string set
添加或编辑应用设置:
az webapp config connection-string set \
--name "<appName>" \
--resource-group "<groupName>" \
--connection-string-type "<connectionType>" \
--settings <connectionName>='<connectionString>'
从应用设置实现连接字符串检索
若要使用以下代码示例,需要以下附加库:
Microsoft.Extensions.Configuration
NuGet 包Microsoft.Extensions.Configuration.EnvironmentVariables
NuGet 包
这些代码示例使用 Redis 数据库,但你可以将其应用于支持连接字符串的任何矢量数据库。
在生成配置时添加环境变量,这会将连接字符串映射到
IConfigurationRoot
对象:// User secrets let you provide connection strings when testing locally // For more info see: https://learn.microsoft.com/en-us/aspnet/core/security/app-secrets IConfigurationRoot config = new ConfigurationBuilder() .AddUserSecrets<Program>() .AddEnvironmentVariables() .Build(); // Retrieve the Redis connection string obtained from the app settings. // The connection string name should match the entry in application settings string redisConnectionString = config.GetConnectionString("AZURE_REDIS")!;
使用应用设置中的矢量数据库连接字符串初始化
IMemoryStore
对象,然后使用该对象生成ISemanticTextMemory
:// Use the connection string to connect to the database IDatabase database = ( await ConnectionMultiplexer.ConnectAsync(redisConnectionString) ).GetDatabase(); // The Semantic Kernel SDK provides a connector extension for Redis. // Initialize an RedisMemoryStore using your managed identity credentials. IMemoryStore memoryStore = new RedisMemoryStore(database); // Retrieve the endpoint and deployments obtained from the Azure OpenAI deployment. // Must use the deployment name not the underlying model name. string openAiEndpoint = config["AZURE_OPENAI_ENDPOINT"]!; string embeddingModel = config["AZURE_OPENAI_EMBEDDING_NAME"]!; // Build a SemanticMemoryStore with Azure AI Search as the store. // Must also include a text embedding generation service. ISemanticTextMemory memory = new MemoryBuilder() .WithOpenAITextEmbeddingGeneration(embeddingModel, openAiEndpoint) .WithMemoryStore(memoryStore) .Build();
生成
Kernel
对象,然后使用TextMemoryPlugin
导入ISemanticTextMemory
对象:// Build a Kernel, include a chat completion service. string chatModel = config["AZURE_OPENAI_GPT_NAME"]!; Kernel kernel = Kernel .CreateBuilder() .AddAzureOpenAIChatCompletion(chatModel, openAiEndpoint, credentials) .Build(); // Import the semantic memory store as a TextMemoryPlugin. // The TextMemoryPlugin enable recall via prompt expressions. kernel.ImportPluginFromObject(new TextMemoryPlugin(memory));
使用
Kernel
对象调用一个包含记忆回忆的提示:// Must configure the memory collection, number of memories to recall, and relevance score. // The {{...}} syntax represents an expression to Semantic Kernel. // For more information on this syntax see: // https://learn.microsoft.com/semantic-kernel/prompts/prompt-template-syntax string memoryCollection = config["AZURE_OPENAI_MEMORY_NAME"]!; string? result = await kernel.InvokePromptAsync<string>( "{{recall 'where did I grow up?'}}", new() { [TextMemoryPlugin.CollectionParam] = memoryCollection, [TextMemoryPlugin.LimitParam] = "2", [TextMemoryPlugin.RelevanceParam] = "0.79", } ); Console.WriteLine($"Output: {result}");
相关内容
- [通过语义内核 SDK 将 Redis 用于记忆存储]
- 如何使用应用程序服务和 Azure Functions 的托管标识
- 分配 Azure 角色的步骤