在 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 accounts
和 Microsoft Personal accounts
登录的用户,请查看 code samples。
我使用默认模板创建了一个 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 accounts
和 Microsoft Personal accounts
登录的用户,请查看 code samples。