【问题标题】:ASP.NET Core 5 WebAPI - Azure AD - Call Graph API Using Azure Ad Access TokenASP.NET Core 5 WebAPI - Azure AD - 使用 Azure 广告访问令牌调用图形 API
【发布时间】:2021-10-30 05:30:44
【问题描述】:

我使用 .NET 5 创建了一个 WebAPI,使用 Azure AD 对用户进行身份验证。我正在使用 Postman 生成访问令牌,并且在将访问令牌作为承载传递时 WebAPI Works。

我想调用 Graph API 以使用访问令牌获取用户日历和个人资料,但无法这样做。我没有运气关注下面提到的几篇文章。

使用访问令牌调用 /me Graph API 时出现无效的身份验证令牌错误

应用注册以仅使用 My Org。我已经为 Graph API 添加了 Delegated 权限。

使用 Expose An API 创建了一个自定义范围,因为 WebAPI 抛出签名无效错误。

我的 WebAPI 在 StartUp.cs 代码中配置服务:

services.AddMicrosoftIdentityWebApiAuthentication(Configuration);

我的 AppSettings.json

  "AzureAd": {
    "Instance": "https://login.microsoftonline.com/",
    "Domain": "<Domain",
    "ClientId": "<ClientId>",
    "TenantId": "<TenantId>"
  },

我曾尝试关注几篇建议代表流量的文章

https://joonasw.net/view/azure-ad-on-behalf-of-aspnet-core

Struggle with MS Graph and asp.net Core API

非常感谢任何帮助。

编辑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();

我可以阅读我的个人资料,但无法获取日历项目。这可能是由于管理员同意要求。

【问题讨论】:

  • 请您尝试一下解决方案,让我知道它是否真的有效。
  • @MdFaridUddinKiron:非常感谢您提供帮助并提供解决方案。我正在尝试,如果有效,我会通知您。
  • 我很高兴,让我更新,即使您需要进一步的帮助。
  • 您好,请问还有什么需要我帮忙的吗?
  • @MdFaridUddinKiron 这是我正在构建的 .NET 5 WebAPI 并且 .AddMicrosoftIdentityWebApp 似乎不可用。需要安装任何特定的软件包吗?

标签: c# azure-active-directory asp.net-core-mvc microsoft-graph-api asp.net-core-webapi


【解决方案1】:

根据您提供的信息,您的令牌似乎已过期,因此首先尝试重新生成它,此外,您已经添加了 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();
        }

注意:您可以忽略ConfigureServicesstartup.cs下的两个服务.EnableTokenAcquisitionToCallDownstreamApi(initialScopes) .AddMicrosoftGraph(Configuration.GetSection("DownstreamApi")) 因为我正在使用Graph API SDK 和阅读范围 appsettings.json 所以在示例中我为您使用本地范围 测试用例。所以它不是必需的或取决于你。

控制器动作:

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;
            }

        }

输出:

注意:完整解决方案请访问GitHub Link

希望它能帮助您实现目标。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-10-07
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-11-12
    • 1970-01-01
    • 2020-12-21
    • 2018-01-15
    相关资源
    最近更新 更多