如何为Azure应用程序服务的特定用户分配的托管服务标识获取令牌?

如何为Azure应用程序服务的特定用户分配的托管服务标识获取令牌?,azure,azure-active-directory,azure-web-app-service,azure-managed-identity,Azure,Azure Active Directory,Azure Web App Service,Azure Managed Identity,我正在尝试获取特定用户定义标识的msi令牌。我们的应用程序服务有2个用户定义的标识,我想要一个代表其中一个用户指定标识的令牌 public static async Task<HttpResponseMessage> GetToken(string resource, string apiversion, string clientId) { HttpClient client = new HttpClient(); client.DefaultReques

我正在尝试获取特定用户定义标识的msi令牌。我们的应用程序服务有2个用户定义的标识,我想要一个代表其中一个用户指定标识的令牌

public static async Task<HttpResponseMessage> GetToken(string resource, string apiversion, string clientId)  
{
    HttpClient client = new HttpClient();   
    client.DefaultRequestHeaders.Add("Secret", Environment.GetEnvironmentVariable("MSI_SECRET"));
    return await client.GetAsync(String.Format("{0}/?resource={1}&api-version={2}&clientid={3}", Environment.GetEnvironmentVariable("MSI_ENDPOINT"), resource, apiversion,clientId));
}
代码如下:

        HttpWebRequest req = (HttpWebRequest)WebRequest.Create(
            "http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https://management.azure.com/&object_id=<ObjectId>&client_id=<clientId>");

        req.Headers["Metadata"] = "true";
        req.Method = "GET";

        try
        {
            // Call /token endpoint
            HttpWebResponse response = (HttpWebResponse)req.GetResponse();

            // Pipe response Stream to a StreamReader, and extract access token
            StreamReader streamResponse = new StreamReader(response.GetResponseStream());
            string stringResponse = streamResponse.ReadToEnd();
            Dictionary<string, string> list =
                 JsonConvert.DeserializeObject<Dictionary<string, string>>(stringResponse);
            string accessToken = list["access_token"];

            System.IO.File.WriteAllText(@".\Log.txt", accessToken);
        }
        catch (Exception e)
        {
            string errorText = String.Format("{0} \n\n{1}", e.Message, e.InnerException != null ? e.InnerException.Message : "Acquire token failed");
            System.IO.File.WriteAllText(@".\Log.txt", errorText);
            throw;
        }
public static async Task<HttpResponseMessage> GetToken(string resource, string apiversion, string clientId)  
{
    HttpClient client = new HttpClient();   
    client.DefaultRequestHeaders.Add("Secret", Environment.GetEnvironmentVariable("MSI_SECRET"));
    return await client.GetAsync(String.Format("{0}/?resource={1}&api-version={2}&clientid={3}", Environment.GetEnvironmentVariable("MSI_ENDPOINT"), resource, apiversion,clientId));
}
它部署在azure应用程序服务中。当我点击此部分时,我看到以下错误: 试图以其访问权限所禁止的方式访问套接字

public static async Task<HttpResponseMessage> GetToken(string resource, string apiversion, string clientId)  
{
    HttpClient client = new HttpClient();   
    client.DefaultRequestHeaders.Add("Secret", Environment.GetEnvironmentVariable("MSI_SECRET"));
    return await client.GetAsync(String.Format("{0}/?resource={1}&api-version={2}&clientid={3}", Environment.GetEnvironmentVariable("MSI_ENDPOINT"), resource, apiversion,clientId));
}
我尝试使用kudu控制台连接到以获取令牌。但在那里似乎无法访问该端点

public static async Task<HttpResponseMessage> GetToken(string resource, string apiversion, string clientId)  
{
    HttpClient client = new HttpClient();   
    client.DefaultRequestHeaders.Add("Secret", Environment.GetEnvironmentVariable("MSI_SECRET"));
    return await client.GetAsync(String.Format("{0}/?resource={1}&api-version={2}&clientid={3}", Environment.GetEnvironmentVariable("MSI_ENDPOINT"), resource, apiversion,clientId));
}
我确实尝试使用Microsoft.Azure.Services.AppAuthentication中的AzureServiceTokenProvider生成msi令牌,但找不到有关如何将其用于多个用户分配身份的任何文档

public static async Task<HttpResponseMessage> GetToken(string resource, string apiversion, string clientId)  
{
    HttpClient client = new HttpClient();   
    client.DefaultRequestHeaders.Add("Secret", Environment.GetEnvironmentVariable("MSI_SECRET"));
    return await client.GetAsync(String.Format("{0}/?resource={1}&api-version={2}&clientid={3}", Environment.GetEnvironmentVariable("MSI_ENDPOINT"), resource, apiversion,clientId));
}
编辑:

public static async Task<HttpResponseMessage> GetToken(string resource, string apiversion, string clientId)  
{
    HttpClient client = new HttpClient();   
    client.DefaultRequestHeaders.Add("Secret", Environment.GetEnvironmentVariable("MSI_SECRET"));
    return await client.GetAsync(String.Format("{0}/?resource={1}&api-version={2}&clientid={3}", Environment.GetEnvironmentVariable("MSI_ENDPOINT"), resource, apiversion,clientId));
}
更新1:

public static async Task<HttpResponseMessage> GetToken(string resource, string apiversion, string clientId)  
{
    HttpClient client = new HttpClient();   
    client.DefaultRequestHeaders.Add("Secret", Environment.GetEnvironmentVariable("MSI_SECRET"));
    return await client.GetAsync(String.Format("{0}/?resource={1}&api-version={2}&clientid={3}", Environment.GetEnvironmentVariable("MSI_ENDPOINT"), resource, apiversion,clientId));
}
我尝试使用MSI_endpoint环境变量中的endpoint,而不是169.254.169.254。但在我运行应用程序服务时,似乎没有设置MSI_端点值。 以下是我尝试过的代码:

   var endpoint = Environment.GetEnvironmentVariable("MSI_ENDPOINT");
    string apiVersion = "2018-02-01";
    string resource = "https://management.azure.com/";
    string objectId = "<objectid>";
    string clientId = "<clientId>";

        // Build request to acquire managed identities for Azure resources token
        //HttpWebRequest req = (HttpWebRequest)WebRequest.Create(
        //    "http://169.254.169.254/metadata/identity/oauth2/token?api-version=2018-02-01&resource=https://management.azure.com/&object_id=4aef1720-b3b1-4935-8d68-e330508907fa&client_id=558ecc75-8697-4419-bab9-aa2c87043cfd");

        HttpWebRequest req = (HttpWebRequest)WebRequest.Create(
       String.Format(
            "{0}?resource={1}&api-version={2}&object_id={3}&client_id={4}",
            endpoint,
            resource,
            apiVersion,
            objectId,
            clientId));

        req.Headers["Metadata"] = "true";
        req.Method = "GET";

        try
        {
            // Call /token endpoint
            HttpWebResponse response = (HttpWebResponse)req.GetResponse();

            // Pipe response Stream to a StreamReader, and extract access token
            StreamReader streamResponse = new StreamReader(response.GetResponseStream());
            string stringResponse = streamResponse.ReadToEnd();
            Dictionary<string, string> list =
                 JsonConvert.DeserializeObject<Dictionary<string, string>>(stringResponse);
            string accessToken = list["access_token"];

            System.IO.File.WriteAllText(@".\Log.txt", accessToken);
        }
        catch (Exception e)
        {
            string errorText = String.Format("{0} \n\n{1}", e.Message, e.InnerException != null ? e.InnerException.Message : "Acquire token failed");

            string log = "MSI_ENDPOINT : " + endpoint + "\n";
            log += ("ErrorText : " + errorText + "\n");
            System.IO.File.WriteAllText(@".\Log.txt", errorText);
            throw;
        }
public static async Task<HttpResponseMessage> GetToken(string resource, string apiversion, string clientId)  
{
    HttpClient client = new HttpClient();   
    client.DefaultRequestHeaders.Add("Secret", Environment.GetEnvironmentVariable("MSI_SECRET"));
    return await client.GetAsync(String.Format("{0}/?resource={1}&api-version={2}&clientid={3}", Environment.GetEnvironmentVariable("MSI_ENDPOINT"), resource, apiversion,clientId));
}
首先,这个链接为MSI应用服务提供了很好的文档

public static async Task<HttpResponseMessage> GetToken(string resource, string apiversion, string clientId)  
{
    HttpClient client = new HttpClient();   
    client.DefaultRequestHeaders.Add("Secret", Environment.GetEnvironmentVariable("MSI_SECRET"));
    return await client.GetAsync(String.Format("{0}/?resource={1}&api-version={2}&clientid={3}", Environment.GetEnvironmentVariable("MSI_ENDPOINT"), resource, apiversion,clientId));
}
下面是快速示例代码。。如您在问题中所问,获取特定用户分配的托管服务标识的令牌

public static async Task<HttpResponseMessage> GetToken(string resource, string apiversion, string clientId)  
{
    HttpClient client = new HttpClient();   
    client.DefaultRequestHeaders.Add("Secret", Environment.GetEnvironmentVariable("MSI_SECRET"));
    return await client.GetAsync(String.Format("{0}/?resource={1}&api-version={2}&clientid={3}", Environment.GetEnvironmentVariable("MSI_ENDPOINT"), resource, apiversion,clientId));
}
resource—应该为其获取令牌的资源的AAD资源URI。 apiversion—要使用的令牌API的版本。2017-09-01是目前唯一受支持的版本。 clientId—要使用的用户指定标识的ID。如果省略,则使用系统分配的标识

public static async Task<HttpResponseMessage> GetToken(string resource, string apiversion, string clientId)  
{
    HttpClient client = new HttpClient();   
    client.DefaultRequestHeaders.Add("Secret", Environment.GetEnvironmentVariable("MSI_SECRET"));
    return await client.GetAsync(String.Format("{0}/?resource={1}&api-version={2}&clientid={3}", Environment.GetEnvironmentVariable("MSI_ENDPOINT"), resource, apiversion,clientId));
}
总的来说,我在上面的示例代码中看到了一些您应该注意到的更改:

public static async Task<HttpResponseMessage> GetToken(string resource, string apiversion, string clientId)  
{
    HttpClient client = new HttpClient();   
    client.DefaultRequestHeaders.Add("Secret", Environment.GetEnvironmentVariable("MSI_SECRET"));
    return await client.GetAsync(String.Format("{0}/?resource={1}&api-version={2}&clientid={3}", Environment.GetEnvironmentVariable("MSI_ENDPOINT"), resource, apiversion,clientId));
}
使用MSI_端点在运行时构造URL 参数应为clientid,而不是客户端id 不需要参数对象\u id api版本应为2017-09-01,因为上述链接中的文档说明这是唯一受支持的版本。 关于您在运行应用程序服务时未设置MSI_端点值的问题,请查看Microsoft文档中同一链接中的此说明

public static async Task<HttpResponseMessage> GetToken(string resource, string apiversion, string clientId)  
{
    HttpClient client = new HttpClient();   
    client.DefaultRequestHeaders.Add("Secret", Environment.GetEnvironmentVariable("MSI_SECRET"));
    return await client.GetAsync(String.Format("{0}/?resource={1}&api-version={2}&clientid={3}", Environment.GetEnvironmentVariable("MSI_ENDPOINT"), resource, apiversion,clientId));
}
与使用的所有参数相关的文档截图

public static async Task<HttpResponseMessage> GetToken(string resource, string apiversion, string clientId)  
{
    HttpClient client = new HttpClient();   
    client.DefaultRequestHeaders.Add("Secret", Environment.GetEnvironmentVariable("MSI_SECRET"));
    return await client.GetAsync(String.Format("{0}/?resource={1}&api-version={2}&clientid={3}", Environment.GetEnvironmentVariable("MSI_ENDPOINT"), resource, apiversion,clientId));
}
首先,这个链接为MSI应用服务提供了很好的文档

public static async Task<HttpResponseMessage> GetToken(string resource, string apiversion, string clientId)  
{
    HttpClient client = new HttpClient();   
    client.DefaultRequestHeaders.Add("Secret", Environment.GetEnvironmentVariable("MSI_SECRET"));
    return await client.GetAsync(String.Format("{0}/?resource={1}&api-version={2}&clientid={3}", Environment.GetEnvironmentVariable("MSI_ENDPOINT"), resource, apiversion,clientId));
}
下面是快速示例代码。。如您在问题中所问,获取特定用户分配的托管服务标识的令牌

public static async Task<HttpResponseMessage> GetToken(string resource, string apiversion, string clientId)  
{
    HttpClient client = new HttpClient();   
    client.DefaultRequestHeaders.Add("Secret", Environment.GetEnvironmentVariable("MSI_SECRET"));
    return await client.GetAsync(String.Format("{0}/?resource={1}&api-version={2}&clientid={3}", Environment.GetEnvironmentVariable("MSI_ENDPOINT"), resource, apiversion,clientId));
}
resource—应该为其获取令牌的资源的AAD资源URI。 apiversion—要使用的令牌API的版本。2017-09-01是目前唯一受支持的版本。 clientId—要使用的用户指定标识的ID。如果省略,则使用系统分配的标识

public static async Task<HttpResponseMessage> GetToken(string resource, string apiversion, string clientId)  
{
    HttpClient client = new HttpClient();   
    client.DefaultRequestHeaders.Add("Secret", Environment.GetEnvironmentVariable("MSI_SECRET"));
    return await client.GetAsync(String.Format("{0}/?resource={1}&api-version={2}&clientid={3}", Environment.GetEnvironmentVariable("MSI_ENDPOINT"), resource, apiversion,clientId));
}
总的来说,我在上面的示例代码中看到了一些您应该注意到的更改:

public static async Task<HttpResponseMessage> GetToken(string resource, string apiversion, string clientId)  
{
    HttpClient client = new HttpClient();   
    client.DefaultRequestHeaders.Add("Secret", Environment.GetEnvironmentVariable("MSI_SECRET"));
    return await client.GetAsync(String.Format("{0}/?resource={1}&api-version={2}&clientid={3}", Environment.GetEnvironmentVariable("MSI_ENDPOINT"), resource, apiversion,clientId));
}
使用MSI_端点在运行时构造URL 参数应为clientid,而不是客户端id 不需要参数对象\u id api版本应为2017-09-01,因为上述链接中的文档说明这是唯一受支持的版本。 关于您在运行应用程序服务时未设置MSI_端点值的问题,请查看Microsoft文档中同一链接中的此说明

public static async Task<HttpResponseMessage> GetToken(string resource, string apiversion, string clientId)  
{
    HttpClient client = new HttpClient();   
    client.DefaultRequestHeaders.Add("Secret", Environment.GetEnvironmentVariable("MSI_SECRET"));
    return await client.GetAsync(String.Format("{0}/?resource={1}&api-version={2}&clientid={3}", Environment.GetEnvironmentVariable("MSI_ENDPOINT"), resource, apiversion,clientId));
}
与使用的所有参数相关的文档截图

public static async Task<HttpResponseMessage> GetToken(string resource, string apiversion, string clientId)  
{
    HttpClient client = new HttpClient();   
    client.DefaultRequestHeaders.Add("Secret", Environment.GetEnvironmentVariable("MSI_SECRET"));
    return await client.GetAsync(String.Format("{0}/?resource={1}&api-version={2}&clientid={3}", Environment.GetEnvironmentVariable("MSI_ENDPOINT"), resource, apiversion,clientId));
}

由于您正在将MSI与应用程序服务一起使用。。您可能应该尝试使用环境变量MSI_ENDPOINT。看看这里的C代码示例,了解如何构造URL-。。类似于String.Format{0}/?resource={1}&api version={2}&object_id={3}&client_id={4},Environment.getEnvironmentVariablesI_端点,resource,apiversion,objectId,clientId;我确实看过MSI端点。价值是。所以我把URL改成了?api version=2018-02-01&resource=>Now I get error无法连接到远程服务器。可能无法访问终结点。好的,我知道了。。我认为URL应该在运行时使用变量构建,就像链接显示中的代码示例一样。。除了输入127.0.0.1,还可以尝试在URL的查询字符串参数中仅传递clientid,而不是objectId。。我认为当我在运行时构造它时,应该是clientid=其中有client\u id=。未设置MSI_终结点。在Kudu控制台上,我看到MSI_ENDPOINT环境变量的值已设置,但当应用程序服务运行时,MSI_ENDPOINT的值未设置。您可能需要重新启动应用程序或重新部署代码。。请参阅Microsoft文档中的此说明。。环境变量是在进程首次启动时设置的,因此在为应用程序启用托管标识后,您可能需要重新启动应用程序或重新部署其代码,然后代码才能使用MSI_ENDPOINT和MSI_SECRET。因为您将MSI与App Service一起使用。。您可能应该尝试使用环境变量MSI_ENDPOINT。看看这里的C代码示例,了解如何构造URL-。。类似于String.Format{0}/?resource={1}&api version={2}&object_id={3}&client_id={4},Environment.getEnvironmentVariablesI_端点,resource,apiversion,objectId,cl
叶状体;我确实看过MSI端点。价值是。所以我把URL改成了?api version=2018-02-01&resource=>Now I get error无法连接到远程服务器。可能无法访问终结点。好的,我知道了。。我认为URL应该在运行时使用变量构建,就像链接显示中的代码示例一样。。除了输入127.0.0.1,还可以尝试在URL的查询字符串参数中仅传递clientid,而不是objectId。。我认为当我在运行时构造它时,应该是clientid=其中有client\u id=。未设置MSI_终结点。在Kudu控制台上,我看到MSI_ENDPOINT环境变量的值已设置,但当应用程序服务运行时,MSI_ENDPOINT的值未设置。您可能需要重新启动应用程序或重新部署代码。。请参阅Microsoft文档中的此说明。。环境变量是在进程首次启动时设置的,因此在为应用程序启用托管标识后,您可能需要重新启动应用程序或重新部署其代码,然后代码才能使用MSI_端点和MSI_SECRET。