在 asp.net 核心 2.2 mvc 应用程序中获取 AzureAD 刷新令牌

Obtaining AzureAD Refresh token in asp.net core 2.2 mvc app

我使用默认模板创建了一个 asp.net 核心 2.2 mvc 应用程序,该应用程序添加了通过工作或学校帐户进行的身份验证,配置如下:

            var azureAD = config.GetSection("AzureAD").Get<AzureADSettings>();
            if (azureAD.Enabled)
            {
                services.AddAuthentication(AzureADDefaults.AuthenticationScheme).AddAzureAD(options =>
                {
                    config.Bind("AzureAd", options);
                });
                services.Configure<OpenIdConnectOptions>(AzureADDefaults.OpenIdScheme, options =>
                {
                    options.ResponseType = azureAD.ResponseType; //"token id_token"
                    options.Resource = azureAD.Resource; //"resource link, dynamics in my case"
                    options.SaveTokens = azureAD.SaveTokens; //"true"
                    options.Scope.Add(azureAD.Scope); //"offline_access"
                });
            }

在我的控制器中,我使用以下代码获取访问令牌:

var accessToken = await _httpContext.GetTokenAsync("access_token");

然后我在 ODataLibrary 中使用此访问令牌从 Dynamics 365 Finance and Operations 访问数据:

            _dataServiceContext.SendingRequest2 += new EventHandler<SendingRequest2EventArgs>(async delegate (object sender, SendingRequest2EventArgs e)
            {
                var accessToken = await dynamicsToken.GetAccessToken();
                e.RequestMessage.SetHeader(OAuthHelper.OAuthHeader, $"Bearer {accessToken}");
            });

一开始它工作正常,但后来我开始收到 401 未经授权的状态代码,我认为这是因为访问令牌已过期,所以我尝试使用刷新令牌获取一个新的:

var accessToken = await _httpContext.GetTokenAsync("access_token");

            var tokenHandler = new JwtSecurityTokenHandler();

            var jwtSecurityToken = tokenHandler.ReadJwtToken(accessToken);

            if (jwtSecurityToken.ValidTo < DateTime.UtcNow.AddHours(1))
            {
                using (var httpClient = new HttpClient())
                {
                    var formContent = new FormUrlEncodedContent(new[]
                    {
                        new KeyValuePair<string, string>("grant_type", "refresh_token"),
                        new KeyValuePair<string, string>("client_id", "client id from azure ad"),
                        new KeyValuePair<string, string>("client_secret", "client secret from azure ad"),
                        new KeyValuePair<string, string>("resource", "resource link"),
                        new KeyValuePair<string, string>("scope", "offline_access"),
                        new KeyValuePair<string, string>("refresh_token", await _httpContext.GetTokenAsync("refresh_token"))

                    });
                    var response = await httpClient.PostAsync("https://login.microsoftonline.com/common/oauth2/token", formContent);
                    response.EnsureSuccessStatusCode();
                    var newAccessToken = await response.Content.ReadAsStringAsync();
                    return newAccessToken;
                }
            }
            else
            {
                return await _httpContext.GetTokenAsync("access_token");
            }

但是 _httpContext.GetTokenAsync("refresh_token") 只是 returns 空。是我配置不正确还是我没有收到刷新令牌的原因是什么?

您正在使用 Implicit grant flow 因为响应类型是 token id_token .

您的 ID 令牌和访问令牌立即从授权端点返回到您的客户端应用程序,而无需向授权端点发出第二个请求。

隐式授权允许应用从 Microsoft 标识平台获取令牌,而无需执行后端服务器凭据交换,这在 AngularJS、Ember.js、React.js 和 React.js 中很常见很快 。这些应用程序的安全特性与传统的基于服务器的 Web 应用程序有很大不同。还有隐式授权 does not provide refresh tokens.

如果使用asp.net核心,建议使用authorization code flow。您可以从以下位置找到代码示例:

https://github.com/Azure-Samples/active-directory-dotnet-webapp-webapi-openidconnect-aspnetcore

注意:以上示例适用于 Azure AD v1.0。如果您正在寻找 Azure AD v2.0 示例(使用 Work and School accountsMicrosoft Personal accounts 登录的用户,请查看 code samples