应用的身份验证方法
本文内容
适用于:✅Azure 数据资源管理器
本文档概述了 Kusto 客户端库可用的身份验证方法的主要方法。 提供的代码片段演示了对用户和应用进行身份验证的不同方法,从而实现与 Kusto 群集的无缝交互。 每种方法适用于不同的应用场景和要求。
如果可能,我们建议使用托管标识,而不是用户名和密码身份验证或连接字符串。 托管标识提供更安全、更简化的身份验证方法。
本文介绍如何使用以下各项进行身份验证:
先决条件
应用程序主体身份验证方法
本部分介绍使用应用程序主体进行身份验证的不同方法。
托管标识身份验证
有两种类型的托管标识:系统分配的托管标识和用户分配的托管标识。 系统分配的托管标识的生命周期与创建它们的资源相关联。 此标识仅限于一个资源。 而用户分配的托管标识可用于多个资源。 有关详细信息,请参阅托管标识 。
| 在以下示例中,将 <QueryEndpointUri>
和 <ManagedIdentityClientId>
替换为自己的值。
重要
必须为托管标识资源的对象或主体 ID 分配一个角色才能访问 Kusto 群集。 可以在 Azure 门户的 Kusto 群集资源页中的“安全性 + 网络” >“权限” 下执行此操作。 不应将托管标识直接附加到 Kusto 群集。
不支持在本地开发环境中进行托管标识身份验证。 若要测试托管标识身份验证,请将应用程序部署到 Azure,或者在本地工作时使用不同的身份验证方法。
基于证书的身份验证
在请求令牌时,可以将证书用作机密来对应用程序的标识进行身份验证。 有多种方法可以加载证书,例如从计算机的本地凭证存储或磁盘加载证书。
| 在以下示例中,将 <QueryEndpointUri>
、<ApplicationId>
、<CertificateSubjectName>
、<CertificateIssuerName>
、<CertificateThumbprint>
、<CertificateObject>
、<AuthorityId>
、<PemPublicCertificate>
、<PemPrivateKey>
、<privateKeyPemFilePath>
、<PemCertificatePath>
和 <EnableSubjectAndIssuerAuth>
替换为自己的值。
仅使用 C# 支持计算机本地证书存储中的证书:
var kcsb = new KustoConnectionStringBuilder(<QueryEndpointUri>)
.WithAadApplicationSubjectAndIssuerAuthentication(<ApplicationId>, <CertificateSubjectName>, <CertificateIssuerName>, <AuthorityId>);
重要
使用使用者名称和颁发者时,证书必须安装在本地计算机的证书存储中。
来自任意源的证书,例如磁盘上的文件、缓存或安全存储(如 Azure Key Vault)。 证书对象必须包含私钥:
X509Certificate2 certificate = <CertificateObject>;
var kcsb = new KustoConnectionStringBuilder(<QueryEndpointUri>)
.WithAadApplicationCertificateAuthentication(<ApplicationId>, certificate, <AuthorityId>);
在内存中加载的证书:
kcsb = KustoConnectionStringBuilder
.with_aad_application_certificate_authentication(<QueryEndpointUri>, <ApplicationId>, <PemPrivateKey>, <CertificateThumbprint>, <AuthorityId>)
使用者和颁发者(SNI)身份验证:
kcsb = KustoConnectionStringBuilder
.with_aad_application_certificate_sni_authentication(<QueryEndpointUri>, <ApplicationId>, <PemPrivateKey>, <PemPublicCertificate>, <CertificateThumbprint>, <AuthorityId>)
在内存中加载的证书,例如从文件加载的证书:
const certificate: string = await fs.promises.readFile(<privateKeyPemFilePath>, "utf8");
const kcsb = KustoConnectionStringBuilder
.withAadApplicationCertificateAuthentication(<QueryEndpointUri>, <ApplicationId>, certificate, <AuthorityId>);
从文件加载证书:
const kcsb = KustoConnectionStringBuilder
.withAadApplicationCertificateAuthentication(<QueryEndpointUri>, <ApplicationId>, undefined, <AuthorityId>, <EnableSubjectAndIssuerAuth>, <PemCertificatePath>);
在内存中加载的证书:
ConnectionStringBuilder kcsb = ConnectionStringBuilder
.createWithAadApplicationCertificate(<QueryEndpointUri>, <ApplicationId>, <X509Certificate>, <PrivateKey>, <AuthorityId>);
使用者和颁发者(SNI)身份验证:
ConnectionStringBuilder kcsb = ConnectionStringBuilder
.createWithAadApplicationCertificateSubjectNameIssuer(<QueryEndpointUri>, <ApplicationId>, <PublicCertificateChain>, <PrivateKey>, <AuthorityId>
有关详细信息,请参阅 Kusto 连接字符串 。
重要
若要从 Azure Key Vault 加载证书,可以使用 Azure.Security.KeyVault.Certificates 客户端 。
应用程序密钥身份验证
应用程序密钥也称为应用程序密码,是应用程序在请求获取令牌时用来进行身份验证和证明自身标识的机密字符串。 它作为应用程序访问受保护资源的一种凭证。 应用程序密钥通常由标识提供者或授权服务器生成和分配。 请务必安全地管理和保护应用程序密钥,以防止敏感信息或操作遭到未经授权的访问。
| 在以下示例中,将 <QueryEndpointUri>
、<ApplicationId>
、<ApplicationKey>
、<AuthorityId>
和 <AuthorityId>
替换为自己的值。
应用程序密钥:
var kcsb = new KustoConnectionStringBuilder(<QueryEndpointUri>)
.WithAadApplicationKeyAuthentication(<ApplicationId>, <ApplicationKey>, <AuthorityId>);
kcsb = KustoConnectionStringBuilder
.with_aad_application_key_authentication(<QueryEndpointUri>, <ApplicationId>, <ApplicationKey>, <AuthorityId>)
const kcsb = KustoConnectionStringBuilder
.withAadApplicationKeyAuthentication(<QueryEndpointUri>, <ApplicationId>, <ApplicationKey>, <AuthorityId>);
ConnectionStringBuilder kcsb = ConnectionStringBuilder
.createWithAadApplicationCredentials(<QueryEndpointUri>, <ApplicationId>, <ApplicationKey>, <AuthorityId>);
包含应用程序密钥的连接字符串:
var connectionString = "Data Source=<QueryEndpointUri>;Initial Catalog=NetDefaultDB;AAD Federated Security=True;AppClientId=<ApplicationId>;AppKey=<ApplicationKey>;Authority Id=<AuthorityId>;"
var kcsb = new KustoConnectionStringBuilder(connectionString);
connectionString = "Data Source=<QueryEndpointUri>;Initial Catalog=NetDefaultDB;AAD Federated Security=True;AppClientId=<ApplicationId>;AppKey=<ApplicationKey>;Authority Id=<AuthorityId>"
kcsb = KustoConnectionStringBuilder(connectionString)
const connectionString = "Data Source=<QueryEndpointUri>;Initial Catalog=NetDefaultDB;AAD Federated Security=True;AppClientId=<ApplicationId>;AppKey=<ApplicationKey>;Authority Id=<AuthorityId>";
const kcsb = new KustoConnectionStringBuilder(connectionString)
String connectionString = "Data Source=<QueryEndpointUri>;AppClientId=<ApplicationId>;AppKey=<ApplicationKey>;Authority Id=<AuthorityId>";
ConnectionStringBuilder kcsb = new ConnectionStringBuilder(connectionString);
重要
在代码中硬编码机密被视为一种不良做法。 以纯文本形式存储敏感信息(如身份验证凭证)可能会导致安全漏洞。 建议保持对敏感信息加密,或将其安全地存储在密钥保管库中。 通过使用加密或密钥保管库,可以确保机密受到保护,并且只有授权用户或应用程序才能访问。
用户主体身份验证方法
本部分介绍使用用户主体进行身份验证的不同方法。
交互式用户登录身份验证
此身份验证方法使用用户的凭证与 Kusto 建立安全连接。 该方法将打开 Web 浏览器,提示用户输入其用户名和密码以完成身份验证过程。
| 在以下示例中,将 <QueryEndpointUri>
、<AuthorityId>
和 <AuthorityId>
替换为自己的值。
交互式用户登录:
var kcsb = new KustoConnectionStringBuilder(<QueryEndpointUri>)
.WithAadUserPromptAuthentication();
kcsb = KustoConnectionStringBuilder
.with_interactive_login(<QueryEndpointUri>)
const kcsb = KustoConnectionStringBuilder
.createWithUserPrompt(<QueryEndpointUri>, {tenantId: <AuthorityId>});
ConnectionStringBuilder kcsb = ConnectionStringBuilder
.createWithAadApplicationCredentials(<QueryEndpointUri>, <AuthorityId>);
Azure 命令行接口 (CLI) 身份验证
此身份验证方法使用 Azure 命令行接口 (CLI) 对用户进行身份验证并为用户获取令牌。 运行 az login
命令意味着用户可以安全地建立连接,并检索必要的令牌以进行身份验证。 如果令牌在 Azure CLI 缓存中不可用且 interactive
参数被设置为 true
,系统可能会提示用户登录。 有关详细信息,请参阅 Azure 命令行接口 (CLI) 。
| 在以下示例中,将 <QueryEndpointUri>
替换为自己的值。
var kcsb = new KustoConnectionStringBuilder(<QueryEndpointUri>)
.WithAadAzCliAuthentication(interactive: true);
kcsb = KustoConnectionStringBuilder
.with_az_cli_authentication(<QueryEndpointUri>)
const kcsb = KustoConnectionStringBuilder
.withAzLoginIdentity(<QueryEndpointUri>);
ConnectionStringBuilder kcsb = ConnectionStringBuilder
.createWithAzureCli(<QueryEndpointUri>);
重要
仅 .NET Framework 应用支持此方法。
设备代码身份验证
此方法适用于缺少用于登录的适当用户界面的设备,例如 IoT 设备和服务器终端。 它为用户提供使用其他设备(例如智能手机)进行身份验证的代码和 URL。 此交互式方法要求用户通过浏览器登录。
| 在以下示例中,将 <QueryEndpointUri>
替换为自己的值。
var kcsb = new KustoConnectionStringBuilder(<QueryEndpointUri>)
.WithAadDeviceCodeAuthentication((msg, uri, code) =>
{
// The callback is used to display instructions to the user on how to authenticate using the device code
Console.WriteLine("Device Code Message: {0}", msg);
Console.WriteLine("Device Code Uri: {0}", uri);
Console.WriteLine("Device Code: {0}", code);
return Task.CompletedTask;
});
kcsb = KustoConnectionStringBuilder
.with_aad_device_authentication(<QueryEndpointUri>)
const kcsb = KustoConnectionStringBuilder
.withAadDeviceAuthentication(<QueryEndpointUri>);
ConnectionStringBuilder kcsb = ConnectionStringBuilder
.createWithDeviceCode(<QueryEndpointUri>);
重要
设备代码身份验证可能会被租户条件访问策略阻止。
如果发生这种情况,请选择备用身份验证方法。
自定义令牌提供程序身份验证方法
本部分介绍使用自定义令牌提供程序进行身份验证的不同方法。
用于联合托管标识凭证身份验证的自定义令牌提供程序
自定义令牌提供程序可用于获取用于身份验证的 Microsoft Entra ID 令牌。 以下示例演示如何使用自定义令牌提供程序,通过联合托管标识获取令牌。 可以修改代码以满足应用程序的要求。
| 在以下示例中,将 <AuthorityIdId>
、<ApplicationId>
、<ManagedIdentityClientId>
和 <QueryEndpointUri>
替换为自己的值。
public class TokenProvider
{
private ClientAssertionCredential m_clientAssertion;
private TokenRequestContext m_tokenRequestContext;
public TokenProvider(string queryEndpointUri)
{
string resourceId = null;
try
{
// Get the appropiate resource id by querying the metadata
var httpClient = new HttpClient();
var response = httpClient.GetByteArrayAsync($"{queryEndpointUri}/v1/rest/auth/metadata").Result;
var json = JObject.Parse(Encoding.UTF8.GetString(response));
resourceId = json["AzureAD"]?["KustoServiceResourceId"]?.ToString();
// Append scope to resource id
resourceId = !string.IsNullOrWhiteSpace(resourceId) ? $"{resourceId}/.default" : null;
}
catch { /* Handle exception */}
m_tokenRequestContext = new TokenRequestContext(new string[] { resourceId ?? "https://kusto.kusto.chinacloudapi.cn/.default" });
// Create client assertion credential to authenticate with Kusto
m_clientAssertion = new ClientAssertionCredential
(
<AuthorityIdId>,
<ApplicationId>,
async (token) =>
{
// Get Managed Identity token
var miCredential = new ManagedIdentityCredential(<ManagedIdentityClientId>);
var miToken = await miCredential.GetTokenAsync(new TokenRequestContext(new[] {
"api://AzureADTokenExchange/.default"
})).ConfigureAwait(false);
return miToken.Token;
}
);
}
public async Task<string> GetTokenAsync()
{
var accessToken = await m_clientAssertion.GetTokenAsync(m_tokenRequestContext).ConfigureAwait(false);
return accessToken.Token;
}
}
var tokenProvider = new TokenProvider(<QueryEndpointUri>);
var kcsb = new KustoConnectionStringBuilder(<QueryEndpointUri>)
.WithAadTokenProviderAuthentication(
async () =>
{
return await tokenProvider.GetTokenAsync();
});
import requests
from azure.identity import ClientAssertionCredential, ManagedIdentityCredential
from azure.kusto.data import KustoConnectionStringBuilder
class TokenProvider:
def __init__(self, query_endpoint_uri):
self.query_endpoint_uri = query_endpoint_uri
self.resource_id = None
self.token_request_context = None
self.client_assertion = None
self._initialize()
def _initialize(self):
try:
# Get the appropriate resource id by querying the metadata
response = requests.get(f"{self.query_endpoint_uri}/v1/rest/auth/metadata")
json = response.json()
self.resource_id = json.get("AzureAD", {}).get("KustoServiceResourceId", "https://kusto.kusto.chinacloudapi.cn")
# Append scope to resource id
self.resource_id = f"{self.resource_id}/.default"
except Exception as error:
print(f"Error fetching metadata: {error}")
self.token_request_context = {"scopes": [self.resource_id or "https://kusto.kusto.chinacloudapi.cn/.default"]}
# Create client assertion credential to authenticate with Kusto
self.client_assertion = ClientAssertionCredential(
tenant_id="<AuthorityId>"
client_id="<ApplicationId>",
func=self._get_managed_identity_token
)
async def _get_managed_identity_token(self):
mi_credential = ManagedIdentityCredential()
mi_token = await mi_credential.get_token("api://AzureADTokenExchange/.default")
return mi_token.token
async def get_token_async(self):
access_token = await self.client_assertion.get_token(self.token_request_context)
return access_token.token
def main():
query_endpoint_uri = "<QueryEndpointUri>"
token_provider = TokenProvider(query_endpoint_uri)
kcsb = KustoConnectionStringBuilder.with_token_provider(
query_endpoint_uri,
token_provider.get_token_async
)
import { ManagedIdentityCredential, ClientAssertionCredential } from '@azure/identity';
import get from 'axios';
import { KustoConnectionStringBuilder } from 'azure-kusto-data';
class TokenProvider {
constructor(queryEndpointUri) {
this.queryEndpointUri = queryEndpointUri;
this.resourceId = null;
this.tokenRequestContext = null;
this.clientAssertion = null;
}
async initialize() {
try {
// Get the appropriate resource id by querying the metadata
const response = await get(`${this.queryEndpointUri}/v1/rest/auth/metadata`);
const json = response.data;
this.resourceId = json.AzureAD?.KustoServiceResourceId || 'https://kusto.kusto.chinacloudapi.cn';
// Append scope to resource id
this.resourceId = `${this.resourceId}/.default`;
} catch (error) {
console.error('Error fetching metadata:', error);
}
this.tokenRequestContext = { scopes: [this.resourceId || 'https://kusto.kusto.chinacloudapi.cn/.default'] };
// Create client assertion credential to authenticate with Kusto
this.clientAssertion = new ClientAssertionCredential(
'<AuthorityId>', // tenantId
'<ApplicationId>', // clientId
async () => {
const miCredential = new ManagedIdentityCredential();
const miToken = await miCredential.getToken({ scopes: ['api://AzureADTokenExchange/.default'] });
return miToken.token;
}
);
}
async getTokenAsync() {
const accessToken = await this.clientAssertion.getToken(this.tokenRequestContext);
return accessToken.token;
}
}
const tokenProvider = new TokenProvider("<QueryEndpointUri>");
await tokenProvider.initialize();
const kcsb = KustoConnectionStringBuilder.withAadTokenProviderAuthentication(
"<QueryEndpointUri>",
async () => {
return await tokenProvider.getTokenAsync();
}
);
public class TokenProvider {
private TokenRequestContext tokenRequestContext;
private ClientAssertionCredential clientAssertion;
public TokenProvider(String queryEndpointUri) {
String resourceId = "";
try {
// Get the appropriate resource id by querying the metadata
URL url = new URL(queryEndpointUri + "/v1/rest/auth/metadata");
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
conn.setRequestMethod("GET");
conn.connect();
Scanner scanner = new Scanner(url.openStream(), StandardCharsets.UTF_8);
String jsonResponse = scanner.useDelimiter("\\A").next();
scanner.close();
ObjectMapper mapper = new ObjectMapper();
JsonNode jsonNode = mapper.readTree(jsonResponse);
resourceId = jsonNode.path("AzureAD").path("KustoServiceResourceId").asText("https://kusto.kusto.chinacloudapi.cn");
// Append scope to resource id
resourceId = resourceId + "/.default";
} catch (IOException e) {
System.err.println("Error fetching metadata: " + e.getMessage());
resourceId = "https://kusto.kusto.chinacloudapi.cn/.default";
}
tokenRequestContext = new TokenRequestContext().addScopes(resourceId);
// Create client assertion credential to authenticate with Kusto
clientAssertion = new ClientAssertionCredential(
"<AuthorityId>",
"<ApplicationId>", // clientId
() -> {
ManagedIdentityCredential miCredential = new ManagedIdentityCredential();
return miCredential.getToken(new TokenRequestContext().addScopes("api://AzureADTokenExchange/.default")).block().getToken();
}
);
}
public CompletableFuture<String> getTokenAsync() {
return clientAssertion.getToken(tokenRequestContext).thenApply(token -> token.getToken());
}
}
TokenProvider tokenProvider = new TokenProvider("<QueryEndpointUri>");
ConnectionStringBuilder kcsb = ConnectionStringBuilder.createWithAadTokenProviderAuthentication(queryEndpointUri,tokenProvider::getTokenAsync);
使用 Azure 令牌凭证身份验证
通过创建继承自 TokenCredential
并实施 GetToken
方法的类来创建自定义令牌提供程序。 或者,可以使用现有的令牌提供程序,如 DefaultAzureCredential
。 当需要自定义令牌提供程序时,此方法为不同的身份验证应用场景提供了灵活性。
可以将 DefaultAzureCredential
用于支持使用托管标识身份验证的生产代码,或使用 Visual Studio 或 Azure CLI 测试代码。 可以将 DefaultAzureCredential
配置为使用不同的身份验证方法。
| 在以下示例中,将 <QueryEndpointUri>
和 <ManagedIdentityClientId>
替换为自己的值。
var credentialProvider = new DefaultAzureCredential(new DefaultAzureCredentialOptions {
ManagedIdentityClientId = <ManagedIdentityClientId>
});
var kcsb = new KustoConnectionStringBuilder(<QueryEndpointUri>)
.WithAadAzureTokenCredentialsAuthentication(credentialProvider);
from azure.identity import DefaultAzureCredential
token_credential = DefaultAzureCredential()
kcsb = KustoConnectionStringBuilder
.with_azure_token_credential(<QueryEndpointUri>, token_credential)
import { DefaultAzureCredential } from "@azure/identity";
const credential = new DefaultAzureCredential();
const kcsb = KustoConnectionStringBuilder
.withTokenCredential(<QueryEndpointUri>, credential);
注意
DefaultAzureCredential
用于向 Azure 服务进行身份验证。
它尝试使用多种身份验证方法来获取令牌,并且可以配置为与托管标识、Visual Studio、Azure CLI 等结合使用。
此凭证同时适用于测试和生产环境,因为它可以设置为使用不同的身份验证方法。
有关详细信息,请参阅 DefaultAzureCredential 类 。
下一步