我有一个使用Azure AD身份验证的应用程序。我还需要访问Microsoft Graph API以获取用户数据。我发现的每个例子都会向Graph API发出请求,使用缓存的会话令牌,但由于我使用的是JWT,所以我不需要存储会话状态。如何使用JWT和我的应用程序作为受众,使用适当的受众获得JWT?
例如,以下是从Microsoft Graph AspNetCore Sample:
中检索令牌的请求_userTokenCache = new SessionTokenCache(userId, _memoryCache).GetCacheInstance();
var cca = new ConfidentialClientApplication(
_appId,
_redirectUri,
_credential,
_userTokenCache,
null);
var result = await cca.AcquireTokenSilentAsync(_scopes, cca.Users.First());
return result.AccessToken;
利用内存缓存从使用OpenId Connect cookie的Challenge()重定向登录中提取令牌。但是,由于我使用的是JWT,我已经拥有了一个不记名的令牌,但是它具有错误的权限。如何获取可用于访问Graph API的新令牌需要做什么?我仍然希望令牌被授权用于我的应用程序ID,所以我想要一个新令牌,允许我通过服务器端休息请求访问API。
编辑:错误地标记为Azure AD Graph,重新标记为Microsoft Graph。
修改编辑:为了澄清,我目前看到的每个示例都使用会话Cookie:
services.AddAuthentication(sharedOptions => {
sharedOptions.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
sharedOptions.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
sharedOptions.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
})
.AddAzureAd(options => Configuration.Bind("AzureAd", options))
.AddCookie();
但是,我正在使用JWT,因此我没有缓存令牌:
app.UseJwtBearerAuthentication(new JwtBearerOptions {
Authority = $"{instance}{tenant}",
Audience = audience,
SaveToken = true
});
我从login.microsoftonline.com
请求获得的JWT将我的申请作为受众,而这些样本生成的JWT以https://graph.microsoft.com
为受众。因此,我只需要使用我从标准身份验证请求中获得的令牌(至少假设)为此受众提供令牌。
答案 0 :(得分:1)
不要混淆如何使用令牌本身管理令牌(即令牌缓存)。您缓存令牌的原因很简单,您可以根据需要请求刷新的令牌(refresh_token
)。刷新令牌仅适用于某些sceanios(即使用authorization_code
流和时,您已请求offline_access
范围。
如果您使用的是没有刷新令牌的流(即implicit
或client_credentials
),那么您可能不需要缓存令牌。您通常应该缓存它们,因为 是从AAD获取令牌的开销成本,而缓存允许您仅在现有令牌到期时检索新令牌。
将DelegateAuthenticationProvider与现有令牌
一起使用所有这一切,听起来你已经拿到了一个令牌。由于MSAL的整个点(ConfidentialClientApplication
来自哪里)它为您检索和管理令牌,我不确定您为什么要这样做。我会完全跳过MSAL,只使用你现有的令牌。
如果您使用Microsoft Graph .NET Client Library,则可以完全放弃MSAL,只需通过access_token
使用现有令牌(DelegateAuthenticationProvider
):
var graphServiceClient = new GraphServiceClient(
new DelegateAuthenticationProvider((requestMessage) => {
requestMessage.Headers.Authorization =
new System.Net.Http.Headers.AuthenticationHeaderValue("bearer", token.access_token);
return Task.FromResult(0);
})
);
至于“适当的观众”,我不确定我是否理解上下文。您的令牌需要包含Microsoft Graph的范围,但您如何定义它们取决于您获取令牌的方式。
v1端点
如果您使用较旧的Azure AD OAUTH端点(也称为v1端点),则需要通过Azure门户配置应用程序权限。要在不同的API(称为“资源”)之间切换,您需要请求offline_access
并使用refresh_token
。切换涉及在传入新的resource
时请求刷新的令牌。然后,生成的令牌将与该资源一起使用。
例如,如果我的默认资源是SharePoint Online实例(https://tenant.sharepoint.com
),那么我通常会使用以下内容刷新令牌:
private async Task<string> RequestTokenAsync() {
var data = new Dictionary<string, string>();
data.Add("grant_type", "refresh_token");
data.Add("client_id", _clientId);
data.Add("client_secret", _clientSecret);
data.Add("resource", "https://tenant.sharepoint.com");
data.Add("redirect_uri", RedirectUri);
data.Add("refresh_token ", refresh_token);
HttpClient httpClient = new HttpClient();
var response = await httpClient.PostAsync(_tokenUri, new FormUrlEncodedContent(data));
response.EnsureSuccessStatusCode();
var result = await result.Content.ReadAsStringAsync();
}
现在,如果我想调用Microsoft Graph,我首先需要获取https://graph.microsoft.com
资源的令牌:
private async Task<string> RequestTokenAsync() {
var data = new Dictionary<string, string>();
data.Add("grant_type", "refresh_token");
data.Add("client_id", _clientId);
data.Add("client_secret", _clientSecret);
data.Add("resource", "https://graph.microsoft.com");
data.Add("redirect_uri", RedirectUri);
data.Add("refresh_token ", refresh_token);
HttpClient httpClient = new HttpClient();
var response = await httpClient.PostAsync(_tokenUri, new FormUrlEncodedContent(data));
response.EnsureSuccessStatusCode();
var result = await result.Content.ReadAsStringAsync();
}
现在我有两个令牌,一个用于SharePoint,一个用于Microsoft Graph。我可以通过简单地刷新适当资源的令牌来切换资源。我必须确保我正确刷新,但是如果我的refresh_token
在我可以替换它之前到期,我就完全丢失了我的凭据。
如果这听起来很复杂,那就是。通常,您需要构建一些机制来管理哪些令牌存在,哪些令牌需要替换等等。这就是令牌缓存的全部内容,因为MSAL / ADAL会为您处理此问题。
v2端点
较新的v2端点更易于使用。而不是resources
它使用scopes
。这些范围包括资源标识符,可以根据需要动态分配。
因此,在v1中,我们可以从Microsoft Graph分配user.read
,从Outlook Rest API分配user.read
,我们现在可以通过请求https://graph.microsoft.com/user.read
和{{在一个令牌中同时分配两者1}}同时。这意味着我们可以获得一个可以与API一起使用的令牌,而无需从上面进入“刷新切换资源”业务。
v2的缺点是目前只有有限数量的API支持它。如果您需要使用多个API,那么由于这个原因,您可能仍然可以更好地使用v1。
希望这会有所帮助。