C# 如何从azure OAuth 2.0令牌(v2)端点获取/生成访问令牌?

C# 如何从azure OAuth 2.0令牌(v2)端点获取/生成访问令牌?,c#,azure,azure-devops,azure-active-directory,C#,Azure,Azure Devops,Azure Active Directory,我想从给定的URL获取访问令牌: https://login.microsoftonline.com/{AzureTenantId}/oauth2/v2.0/token 我正在传递以下参数,如Microsoft文档中所述: 客户id,范围,客户机密,授权类型 当我点击这个URL时,我得到一个“400错误请求”响应 当我从Postman尝试相同操作时,它成功并为我提供了一个访问令牌: 但不是从我的代码: public async Task<string> GetAuthorizat

我想从给定的URL获取访问令牌:

https://login.microsoftonline.com/{AzureTenantId}/oauth2/v2.0/token
我正在传递以下参数,如Microsoft文档中所述:
客户id
范围
客户机密
授权类型

当我点击这个URL时,我得到一个“400错误请求”响应

当我从Postman尝试相同操作时,它成功并为我提供了一个访问令牌:

但不是从我的代码:

public async Task<string> GetAuthorizationToken(string clientId, string ServicePrincipalPassword, string AzureTenantId) {
            var result = "";
            var requestURL = "https://login.microsoftonline.com/{AzureTenantId}/oauth2/v2.0/token";
            var _httpClient = new HttpClient();

            var model = new {
                client_id = clientId,
                scope = "{clentID}/.default",
                client_secret = ServicePrincipalPassword,
                grant_type = "client_credentials"
            };

            HttpContent httpContent = new StringContent(JsonConvert.SerializeObject(model), System.Text.Encoding.UTF8, "application/x-www-form-urlencoded");

            var httpRequestMessage = new HttpRequestMessage(HttpMethod.Post, new Uri(requestURL)) {
                Content = httpContent
            };

            using (var response = await _httpClient.SendAsync(httpRequestMessage)) {
                if (response.IsSuccessStatusCode) {
                    var responseStream = await response.Content.ReadAsStringAsync();
                    return result;
                } else {
                    return result;
                }
            }
公共异步任务GetAuthorizationToken(字符串clientId、字符串ServicePrincipalPassword、字符串AzureTenantId){
var结果=”;
var requestURL=”https://login.microsoftonline.com/{AzureTenantId}/oauth2/v2.0/token”;
varu httpClient=新的httpClient();
var模型=新{
client_id=clientId,
scope=“{clentID}/.default”,
client_secret=ServicePrincipalPassword,
授予\ u type=“客户\凭证”
};
HttpContent HttpContent=new StringContent(JsonConvert.SerializeObject(model),System.Text.Encoding.UTF8,“application/x-www-form-urlencoded”);
var httpRequestMessage=新的httpRequestMessage(HttpMethod.Post,新Uri(requestURL)){
Content=httpContent
};
使用(var response=await_httpClient.sendsync(httpRequestMessage)){
if(响应。IsSuccessStatusCode){
var responseStream=await response.Content.ReadAsStringAsync();
返回结果;
}否则{
返回结果;
}
}
遵循以下步骤

  • 转到应用程序的“公开Api”刀片
  • 找到应用ID URI值。假设应用ID URI为
  • 您要获取的令牌的资源将是
    http://abc.pqr/.default
  • 遵循以下步骤

  • 转到应用程序的“公开Api”刀片
  • 找到应用ID URI值。假设应用ID URI为
  • 您要获取的令牌的资源将是
    http://abc.pqr/.default

  • 您的http请求格式不正确,请尝试:

    var _httpClient = new HttpClient();
    
    var content = new FormUrlEncodedContent(new Dictionary<string, string> {
                  { "client_id", "ClientID" },
                  { "client_secret", "YourSecret" },
                  { "grant_type", "client_credentials" },
                  { "scope", "https://graph.microsoft.com/.default" },
                });
    
    var httpRequestMessage = new HttpRequestMessage(HttpMethod.Post, new Uri(requestURL))
    {
        Content = content
    };
    
    using (var response = await _httpClient.SendAsync(httpRequestMessage))
    {
        if (response.IsSuccessStatusCode)
        {
            var responseStream = await response.Content.ReadAsStringAsync();
            return result;
        }
        else
        {
            return result;
        }
    }
    
    var\u httpClient=new httpClient();
    var content=newformurlencodedcontent(新字典{
    {“客户端id”、“客户端id”},
    {“客户秘密”,“你的秘密”},
    {“授权类型”、“客户端凭据”},
    {“范围”https://graph.microsoft.com/.default" },
    });
    var httpRequestMessage=新的httpRequestMessage(HttpMethod.Post,新Uri(requestURL))
    {
    内容=内容
    };
    使用(var response=await_httpClient.sendsync(httpRequestMessage))
    {
    if(响应。IsSuccessStatusCode)
    {
    var responseStream=await response.Content.ReadAsStringAsync();
    返回结果;
    }
    其他的
    {
    返回结果;
    }
    }
    
    您的http请求格式不正确,请尝试:

    var _httpClient = new HttpClient();
    
    var content = new FormUrlEncodedContent(new Dictionary<string, string> {
                  { "client_id", "ClientID" },
                  { "client_secret", "YourSecret" },
                  { "grant_type", "client_credentials" },
                  { "scope", "https://graph.microsoft.com/.default" },
                });
    
    var httpRequestMessage = new HttpRequestMessage(HttpMethod.Post, new Uri(requestURL))
    {
        Content = content
    };
    
    using (var response = await _httpClient.SendAsync(httpRequestMessage))
    {
        if (response.IsSuccessStatusCode)
        {
            var responseStream = await response.Content.ReadAsStringAsync();
            return result;
        }
        else
        {
            return result;
        }
    }
    
    var\u httpClient=new httpClient();
    var content=newformurlencodedcontent(新字典{
    {“客户端id”、“客户端id”},
    {“客户秘密”,“你的秘密”},
    {“授权类型”、“客户端凭据”},
    {“范围”https://graph.microsoft.com/.default" },
    });
    var httpRequestMessage=新的httpRequestMessage(HttpMethod.Post,新Uri(requestURL))
    {
    内容=内容
    };
    使用(var response=await_httpClient.sendsync(httpRequestMessage))
    {
    if(响应。IsSuccessStatusCode)
    {
    var responseStream=await response.Content.ReadAsStringAsync();
    返回结果;
    }
    其他的
    {
    返回结果;
    }
    }
    < /代码> 作为一个附加项,您可能想考虑为此使用一个库,而不是试图自己实现这个。

    例如,使用.NET的Microsoft身份验证库(MSAL),您将获得如下访问令牌:

    // Setup MSAL
    var client = ConfidentialClientApplicationBuilder
        .Create("{client-id}")
        .WithAuthority("https://login.microsoftonline.com/{tenant-id}/v2.0")
        .WithClientSecret(/* retrieve from secure storage, do *NOT* put the secret in your code! */)
        .Build();
    
    // Retrieve an access token
    var scopes = new string[] { "https://graph.microsoft.com/.default" };
    var authResult = await clientApplication.AcquireTokenForClient(scopes).ExecuteAsync();
    
    // The access token is in $authResult.AccessToken
    
    一个重要的优点是,您无需担心跟踪令牌有效性以知道何时需要获取新令牌。如果需要获取新令牌,只需再次调用
    AcquireTokenForClient
    ,它就会为您确定是否需要获取新令牌,或者是否可以使用已缓存的令牌。

    P>作为一个补充,您可能想考虑为此使用一个库,而不是试图自己实现这个。

    例如,使用.NET的Microsoft身份验证库(MSAL),您将获得如下访问令牌:

    // Setup MSAL
    var client = ConfidentialClientApplicationBuilder
        .Create("{client-id}")
        .WithAuthority("https://login.microsoftonline.com/{tenant-id}/v2.0")
        .WithClientSecret(/* retrieve from secure storage, do *NOT* put the secret in your code! */)
        .Build();
    
    // Retrieve an access token
    var scopes = new string[] { "https://graph.microsoft.com/.default" };
    var authResult = await clientApplication.AcquireTokenForClient(scopes).ExecuteAsync();
    
    // The access token is in $authResult.AccessToken
    

    一个重要的优点是,您无需担心跟踪令牌有效性以知道何时需要获取新令牌。如果需要获取新令牌,只需再次调用
    AcquireTokenForClient
    ,它就会为您确定是否需要获取新令牌,或者是否可以使用已缓存的令牌。

    尝试读取响应流。您应该获得有关错误的更多详细信息。请使用该错误消息更新您的问题。尝试读取响应流。您应该获得有关错误的更多详细信息。请使用该错误消息更新您的问题。有关如何指定grant_type=“client\u凭据”的任何线索使用这种方法?似乎由于它的缺失,我获得了一个令牌,但在使用时它会进入401。但是当通过邮递员请求发送grant_type时,获得的令牌是可以的。使用库的全部意义在于,您不必担心协议细节,例如使用哪个
    grant_type
    值。库将选择根据您如何配置客户端,选择正确的客户端。在本答案中的示例中(使用客户端机密的机密客户端),生成的令牌请求确实使用了
    grant\u type=client\u credentials
    。是的,在我写了评论之后,我查看了方法文档并实现了它。非常感谢。我的问题是,作用域的初始化值与我预期的值不同。但是有一个有趣的问题