ASP.NET Core 5 WebAPI - Azure AD - 调用图 API 使用 Azure 广告访问令牌
ASP.NET Core 5 WebAPI - Azure AD - Call Graph API Using Azure Ad Access Token
我使用 .NET 5 创建了一个 WebAPI,使用 Azure AD 对用户进行身份验证。我正在使用 Postman 生成访问令牌,WebAPI 在将访问令牌作为 Bearer 传递时工作。
我想调用 Graph API 以使用访问令牌获取用户日历和个人资料,但无法这样做。我已经关注了下面提到的几篇文章,但没有运气。
使用访问令牌调用 /me Graph 时出现无效的身份验证令牌错误API
应用程序注册以仅使用我的组织。我已将委派权限添加到 Graph API.
使用 Expose An API 创建自定义作用域,因为 WebAPI 抛出签名无效错误。
My WebAPI 在 StartUp.cs 代码中配置服务:
services.AddMicrosoftIdentityWebApiAuthentication(Configuration);
我的AppSettings.json
"AzureAd": {
"Instance": "https://login.microsoftonline.com/",
"Domain": "<Domain",
"ClientId": "<ClientId>",
"TenantId": "<TenantId>"
},
我已经尝试关注几篇建议 On Behalf Of Flow 的文章
https://joonasw.net/view/azure-ad-on-behalf-of-aspnet-core
我迷路了非常感谢任何帮助。
编辑 1:
我尝试实施 Farid 建议的解决方案。
邮递员输出返回 HTML 登录响应。它是 ASP.NET Core 5 WebAPI 所以我将 ConfigureServices 代码更改为以下内容:
services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApi(Configuration.GetSection("AzureAd"))
.EnableTokenAcquisitionToCallDownstreamApi()
.AddMicrosoftGraph(Configuration.GetSection("DownstreamApi"))
.AddInMemoryTokenCaches();
我收到以下错误。
System.InvalidOperationException: No authenticationScheme was specified, and there was no DefaultChallengeScheme found. The default schemes can be set using either AddAuthentication(string defaultScheme) or AddAuthentication(Action<AuthenticationOptions> configureOptions).
at Microsoft.AspNetCore.Authentication.AuthenticationService.ChallengeAsync(HttpContext context, String scheme, AuthenticationProperties properties)
at Microsoft.AspNetCore.Authorization.Policy.AuthorizationMiddlewareResultHandler.HandleAsync(RequestDelegate next, HttpContext context, AuthorizationPolicy policy, PolicyAuthorizationResult authorizeResult)
at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
at Swashbuckle.AspNetCore.SwaggerUI.SwaggerUIMiddleware.Invoke(HttpContext httpContext)
at Swashbuckle.AspNetCore.Swagger.SwaggerMiddleware.Invoke(HttpContext httpContext, ISwaggerProvider swaggerProvider)
at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)
更新:
我能够使用以下代码解决错误:
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) .AddMicrosoftIdentityWebApi(Configuration.GetSection("AzureAd"))
.EnableTokenAcquisitionToCallDownstreamApi() .AddMicrosoftGraph(Configuration.GetSection("DownstreamApi"))
.AddInMemoryTokenCaches();
我可以阅读我的个人资料,但无法获取日历项目。这可能是由于管理员同意要求。
根据您提供的信息,您的令牌似乎已过期,因此首先尝试重新生成该令牌,此外,您添加了 Delegated permissions
没关系,但我怀疑您在添加 Graph API许可。所以它是强制性的,请仔细检查。请参阅下面的屏幕截图。请按照以下步骤使用 Microsoft Graph API
获取令牌和用户信息
授予管理员同意:
代币获取示例:
检查 appsettings.json
它应该如下所示:
{
"AzureAd": {
"Instance": "https://login.microsoftonline.com/",
"Domain": "yourdemain.onmicrosoft.com",
"TenantId": "",
"ClientId": "",
"ClientSecret": "",
"ClientCertificates": [
],
"CallbackPath": "/signin-oidc"
},
"DownstreamApi": {
"BaseUrl": "https://graph.microsoft.com/v1.0",
"Scopes": "https://graph.microsoft.com/.default"
},
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"AllowedHosts": "*"
}
Startup.cs
public void ConfigureServices(IServiceCollection services)
{
string[] initialScopes = Configuration.GetValue<string>("DownstreamApi:Scopes")?.Split(' ');
services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApp(Configuration.GetSection("AzureAd"))
.EnableTokenAcquisitionToCallDownstreamApi(initialScopes)
.AddMicrosoftGraph(Configuration.GetSection("DownstreamApi"))
.AddInMemoryTokenCaches();
services.AddControllersWithViews(options =>
{
var policy = new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser()
.Build();
options.Filters.Add(new AuthorizeFilter(policy));
});
services.AddRazorPages()
.AddMicrosoftIdentityUI();
}
Note: You can ignore below two service from the ConfigureServices
under startup.cs
.EnableTokenAcquisitionToCallDownstreamApi(initialScopes) .AddMicrosoftGraph(Configuration.GetSection("DownstreamApi"))
because I am using Graph API SDK
and reading scope from
appsettings.json
so in the sample I am using local scope for your
test case. So its not required or upto you.
控制器操作:
public async Task<object> GetUserInfoFromGraphAPI()
{
try
{
//Initialize on behalf of user token aquisition service
var _tokenAcquisition = this.HttpContext.RequestServices.GetRequiredService<ITokenAcquisition>() as ITokenAcquisition;
//define the scope
string[] scopes = new string[] { "https://graph.microsoft.com/.default" };
//Getting token from Azure Active Directory
string accessToken = await _tokenAcquisition.GetAccessTokenForUserAsync(scopes);
//Request Grap API end point
HttpClient _client = new HttpClient();
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, string.Format("https://graph.microsoft.com/v1.0/me"));
//Passing Token For this Request
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);
HttpResponseMessage response = await _client.SendAsync(request);
//Get User into from grpah API
dynamic userInfo = JsonConvert.DeserializeObject<dynamic>(await response.Content.ReadAsStringAsync());
return userInfo;
}
catch (Exception ex)
{
throw;
}
}
输出:
Note: For complete solution please visit the GitHub Link
希望它能帮助您实现目标。
我使用 .NET 5 创建了一个 WebAPI,使用 Azure AD 对用户进行身份验证。我正在使用 Postman 生成访问令牌,WebAPI 在将访问令牌作为 Bearer 传递时工作。
我想调用 Graph API 以使用访问令牌获取用户日历和个人资料,但无法这样做。我已经关注了下面提到的几篇文章,但没有运气。
使用访问令牌调用 /me Graph 时出现无效的身份验证令牌错误API
应用程序注册以仅使用我的组织。我已将委派权限添加到 Graph API.
使用 Expose An API 创建自定义作用域,因为 WebAPI 抛出签名无效错误。
My WebAPI 在 StartUp.cs 代码中配置服务:
services.AddMicrosoftIdentityWebApiAuthentication(Configuration);
我的AppSettings.json
"AzureAd": {
"Instance": "https://login.microsoftonline.com/",
"Domain": "<Domain",
"ClientId": "<ClientId>",
"TenantId": "<TenantId>"
},
我已经尝试关注几篇建议 On Behalf Of Flow 的文章
https://joonasw.net/view/azure-ad-on-behalf-of-aspnet-core
我迷路了非常感谢任何帮助。
编辑 1:
我尝试实施 Farid 建议的解决方案。 邮递员输出返回 HTML 登录响应。它是 ASP.NET Core 5 WebAPI 所以我将 ConfigureServices 代码更改为以下内容:
services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApi(Configuration.GetSection("AzureAd"))
.EnableTokenAcquisitionToCallDownstreamApi()
.AddMicrosoftGraph(Configuration.GetSection("DownstreamApi"))
.AddInMemoryTokenCaches();
我收到以下错误。
System.InvalidOperationException: No authenticationScheme was specified, and there was no DefaultChallengeScheme found. The default schemes can be set using either AddAuthentication(string defaultScheme) or AddAuthentication(Action<AuthenticationOptions> configureOptions).
at Microsoft.AspNetCore.Authentication.AuthenticationService.ChallengeAsync(HttpContext context, String scheme, AuthenticationProperties properties)
at Microsoft.AspNetCore.Authorization.Policy.AuthorizationMiddlewareResultHandler.HandleAsync(RequestDelegate next, HttpContext context, AuthorizationPolicy policy, PolicyAuthorizationResult authorizeResult)
at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)
at Swashbuckle.AspNetCore.SwaggerUI.SwaggerUIMiddleware.Invoke(HttpContext httpContext)
at Swashbuckle.AspNetCore.Swagger.SwaggerMiddleware.Invoke(HttpContext httpContext, ISwaggerProvider swaggerProvider)
at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)
更新:
我能够使用以下代码解决错误:
services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) .AddMicrosoftIdentityWebApi(Configuration.GetSection("AzureAd"))
.EnableTokenAcquisitionToCallDownstreamApi() .AddMicrosoftGraph(Configuration.GetSection("DownstreamApi"))
.AddInMemoryTokenCaches();
我可以阅读我的个人资料,但无法获取日历项目。这可能是由于管理员同意要求。
根据您提供的信息,您的令牌似乎已过期,因此首先尝试重新生成该令牌,此外,您添加了 Delegated permissions
没关系,但我怀疑您在添加 Graph API许可。所以它是强制性的,请仔细检查。请参阅下面的屏幕截图。请按照以下步骤使用 Microsoft Graph API
授予管理员同意:
代币获取示例:
检查 appsettings.json
它应该如下所示:
{
"AzureAd": {
"Instance": "https://login.microsoftonline.com/",
"Domain": "yourdemain.onmicrosoft.com",
"TenantId": "",
"ClientId": "",
"ClientSecret": "",
"ClientCertificates": [
],
"CallbackPath": "/signin-oidc"
},
"DownstreamApi": {
"BaseUrl": "https://graph.microsoft.com/v1.0",
"Scopes": "https://graph.microsoft.com/.default"
},
"Logging": {
"LogLevel": {
"Default": "Information",
"Microsoft": "Warning",
"Microsoft.Hosting.Lifetime": "Information"
}
},
"AllowedHosts": "*"
}
Startup.cs
public void ConfigureServices(IServiceCollection services)
{
string[] initialScopes = Configuration.GetValue<string>("DownstreamApi:Scopes")?.Split(' ');
services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApp(Configuration.GetSection("AzureAd"))
.EnableTokenAcquisitionToCallDownstreamApi(initialScopes)
.AddMicrosoftGraph(Configuration.GetSection("DownstreamApi"))
.AddInMemoryTokenCaches();
services.AddControllersWithViews(options =>
{
var policy = new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser()
.Build();
options.Filters.Add(new AuthorizeFilter(policy));
});
services.AddRazorPages()
.AddMicrosoftIdentityUI();
}
Note: You can ignore below two service from the
ConfigureServices
understartup.cs
.EnableTokenAcquisitionToCallDownstreamApi(initialScopes) .AddMicrosoftGraph(Configuration.GetSection("DownstreamApi"))
because I am usingGraph API SDK
and reading scope fromappsettings.json
so in the sample I am using local scope for your test case. So its not required or upto you.
控制器操作:
public async Task<object> GetUserInfoFromGraphAPI()
{
try
{
//Initialize on behalf of user token aquisition service
var _tokenAcquisition = this.HttpContext.RequestServices.GetRequiredService<ITokenAcquisition>() as ITokenAcquisition;
//define the scope
string[] scopes = new string[] { "https://graph.microsoft.com/.default" };
//Getting token from Azure Active Directory
string accessToken = await _tokenAcquisition.GetAccessTokenForUserAsync(scopes);
//Request Grap API end point
HttpClient _client = new HttpClient();
HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, string.Format("https://graph.microsoft.com/v1.0/me"));
//Passing Token For this Request
request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", accessToken);
HttpResponseMessage response = await _client.SendAsync(request);
//Get User into from grpah API
dynamic userInfo = JsonConvert.DeserializeObject<dynamic>(await response.Content.ReadAsStringAsync());
return userInfo;
}
catch (Exception ex)
{
throw;
}
}
输出:
Note: For complete solution please visit the GitHub Link
希望它能帮助您实现目标。