【问题标题】:How do I get Azure AD OAuth2 Access Token and Refresh token for Daemon or Server to C# ASP.NET Web API如何获取守护进程或服务器到 C# ASP.NET Web API 的 Azure AD OAuth2 访问令牌和刷新令牌
【发布时间】:2017-10-25 00:07:37
【问题描述】:

我已经实现了 Azure AD OAuth2 守护程序或服务器到 ASP.NET Web API。 但是,我只收到一个访问令牌,它是 AuthenticationResult 上的属性。请参阅下面的实现。

    public IHttpActionResult GetAccessToken(string clientId, string clientkey)
    {
        AuthenticationContext authContext = new AuthenticationContext(authority);
        ClientCredential clientCredential = new ClientCredential(clientId, clientkey);
        AuthenticationResult authenticationResult = authContext.AcquireTokenAsync(resourceUri, clientCredential).Result;
        Authorisation authorisation = new Authorisation {access_token = authenticationResult.AccessToken,
                                                token_type = authenticationResult.AccessTokenType,
                                                expires_on = authenticationResult.ExpiresOn };

        return Ok(authorisation);
    }   

这仅返回访问令牌。我想要一个实现,一个守护进程或服务器实现,它返回访问令牌和刷新令牌。您是否看过或做过类似的实现。欢迎任何有用的示例链接。

【问题讨论】:

    标签: c# azure security oauth-2.0 azure-active-directory


    【解决方案1】:

    当我发布此问题时,这就是我正在寻找的答案,请参阅下面的屏幕截图以了解预期结果和 c# 控制台解决方案。 找到解决方案后,值得在这里分享,可能有一天对某人有用

    在下面的邮递员屏幕截图中实现预期结果的 C# 控制台应用程序代码

    using System;
    using System.Collections.Generic;
    using System.Net.Http;
    
    namespace AzureADTokenApp
    {
        class Program
        {
            static void Main(string[] args)
            {
    
                var client = new HttpClient();
                var uri = "https://login.microsoftonline.com/<tenant-name>.onmicrosoft.com/oauth2/token?api-version=1.0";
                var pairs = new List<KeyValuePair<string, string>>
                {
                    new KeyValuePair<string, string>("resource", "https://graph.microsoft.com"),
                    new KeyValuePair<string, string>("client_id", "<azure ad client id e.g. 9b864-a5e6-4f0d-b155-1f53a6c78>"),
                    new KeyValuePair<string, string>("client_secret", "<azure ad client secret e.g. MTMiXaO1P9HnhSawdXWmcnuQ="),
                    new KeyValuePair<string, string>("grant_type", "password"),
                    new KeyValuePair<string, string>("username", "<azure ad user e.g. julius.depulla@example.com>"),
                    new KeyValuePair<string, string>("password", "<azure ad user password e.g. Pa$$word01>"),
                    new KeyValuePair<string, string>("scope", "openid")
                 };
    
                var content = new FormUrlEncodedContent(pairs);
    
                var response = client.PostAsync(uri, content).Result;
    
                string result = string.Empty;
    
                if (response.IsSuccessStatusCode)
                {
    
                    result = response.Content.ReadAsStringAsync().Result;
                }
    
                Console.WriteLine(result);
                Console.ReadLine();
            }
        }
    }
    

    来自 Postman 的屏幕截图 - 预期结果。您将在控制台中获得相同的结果,但可读性较低

    【讨论】:

    • 响应为我显示 400。 tenant-name 是应用程序的实际显示名称吗?
    • tenant-name 是您的 Azure-AD 的名称
    • 如何找到您的租户名称:helpdesk.kaseya.com/hc/en-gb/articles/…
    • 嗨@JuliusDepulla,运行你的代码你能告诉我应该在我的天蓝色目录中设置什么吗?我看到了很多让我很困惑的文档。
    【解决方案2】:

    您正在使用客户端凭据流。在该流程中,不应包含刷新令牌https://www.rfc-editor.org/rfc/rfc6749#section-4.4.3。此外,您似乎正在使用 ADAL v3,它无论如何都不会返回刷新令牌(按设计),但它会自动为您使用它们。更多信息在这里http://www.cloudidentity.com/blog/2015/08/13/adal-3-didnt-return-refresh-tokens-for-5-months-and-nobody-noticed/

    【讨论】:

    • 我想要一个刷新令牌和一个访问令牌,你知道 C# 中可以使用的任何其他库
    • ADAL v2 返回刷新令牌,如果您使用的 OAuth 流程使用它们
    • 你说得对 ADAL v2 确实返回刷新令牌,但 ADAL 现在处于 v3 中,如果我使用 v2,我将错过 ADAL 库的更新/补丁
    • 好吧,我不知道有任何其他的 MS 库。也许有一个非 MS 库。或者,也许您可​​以手动构建获取访问/刷新令牌所需的 HTTP 请求(本质上,与 ADAL 为您执行的操作相同)。但正如我在帖子中提到的博客中所述,ADAL v3 有充分的理由不返回刷新令牌,而是自动为您使用它们。如果您开始一个新的线程/问题来描述您尝试解决的场景以及为什么需要操作刷新令牌而不是让 ADAL 为您操作刷新令牌,也许会有所帮助。
    【解决方案3】:

    如果您使用 ADAL v3 进行开发,则无需使用刷新令牌手动兑换访问令牌。

    在这种情况下,我们应该使用AcquireTokenSilentAsync 并捕获异常。 access_token过期后,需要重新初始化AuthenticationContext,再次调用AcquireTokenAsync发送获取access_token的请求。

    这是一个代码示例供您参考:

    class Program
    {
        static string authority = "https://login.microsoftonline.com/adfei.onmicrosoft.com";
        static string resrouce = "https://graph.microsoft.com";
        static string clientId = "";
        static string secret = "";
        static ClientCredential credential = new ClientCredential(clientId, secret);
        static AuthenticationContext authContext = new AuthenticationContext(authority);
        static void Main(string[] args)
        {
            while (true)
            {
                var client = new GraphServiceClient(new DelegateAuthenticationProvider(request =>
                {
                    request.Headers.Authorization = new AuthenticationHeaderValue("bearer", GetAccessToken());
                    return Task.FromResult(0);
                }));
    
                var users = client.Users.Request().GetAsync().Result.CurrentPage;
                foreach (var user in users)
                {
                    Console.WriteLine(user.DisplayName);
                }          
                Thread.Sleep(1000 * 60 * 5);
            }
            Console.Read();
        }
    
        static string GetAccessToken()
        {
            try
            {
                var token = authContext.AcquireTokenAsync(resrouce, credential).Result.AccessToken;             
                return token;
            }
            catch (Exception ex)
            {
                authContext = new AuthenticationContext(authority);
                return GetAccessToken();
            }
        }
    

    【讨论】:

    • Xue-MSFT AcquireTokenSilentAsync 总是抛出异常 AdalSilentTokenAcquisitionException。如果在您第一次获取访问令牌之前,它会抛出异常,但在访问令牌过期之前的后续请求它会返回访问令牌,这将是一个解决方案
    • @JuliusDepulla 要使AcquireTokenSilentAsync 首次工作,应用程序应在调用AcquireTokenSilentAsync 之前手动调用AcquireTokenAsync。初始化调用AcquireTokenAsync会得到access_token和refresh_token,保证后面调用AcquireTokenSilentAsync成功。
    • Xue-MSFT 我在守护进程/服务器/控制台应用程序中使用 ADAL v3 到 Web API 场景,它不返回访问/刷新令牌。然而 ADAL v2 确实如此。如果您不这么认为,请在此处发布完整的解决方案,我将感谢您的帮助。
    • @JuliusDepulla 对误导感到抱歉。在进一步调查之后,由于客户端凭据流不会返回 refresh_token(请参阅 4.4.3. Access Token Response),因此该场景将不适合您。我们可以重新初始化authContext,并在access_token过期时调用AcquireTokenAsync再次发送获取access_token的请求。我会修改回复,附上代码示例供您参考。
    • Xue-MSFT 非常感谢您的帮助。参考非常有用。期待您的代码示例。问候。
    猜你喜欢
    • 2023-04-04
    • 2020-10-15
    • 2021-03-02
    • 1970-01-01
    • 2019-08-31
    • 2018-10-17
    • 2019-08-25
    • 2016-08-28
    • 1970-01-01
    相关资源
    最近更新 更多