Как настроить Swagger в .NET Core 2.2 WebApi и Azure AD 2.0?

У меня проблема с функцией «авторизации» Swagger для аутентификации приложения WebApi с использованием конечной точки Azure AD 2.0. Я использовал следующие настройки в своем классе запуска, но полученный токен не может проверить токен носителя внутри Swagger. API отлично работает с токеном, отправленным реагирующим клиентом.

private const string AzureAdConfigKey = "AzureAd";
private const string OAuth2Definition = "openid";

private IConfiguration Configuration { get; }
private IHostingEnvironment Environment { get; }

public Startup(IConfiguration configuration, IHostingEnvironment environment)
{
    Environment = environment;
    Configuration = configuration;
}

public void ConfigureServices(IServiceCollection services)
{
    services.AddAuthentication(AzureADDefaults.JwtBearerAuthenticationScheme)
        .AddAzureADBearer(options => Configuration.Bind(AzureAdConfigKey, options));

    services.Configure<JwtBearerOptions>(AzureADDefaults.JwtBearerAuthenticationScheme,
        options => options.Authority += "/v2.0");

    var authorizationPolicy = new AuthorizationPolicyBuilder()
        .RequireAuthenticatedUser()
        .Build();

    services.AddMvc(options => options.Filters.Add(new AuthorizeFilter(authorizationPolicy)))
        .SetCompatibilityVersion(CompatibilityVersion.Version_2_2);

    var azureAdAuthority = $"https://login.microsoftonline.com/{Configuration["AzureAd:TenantId"]}/oauth2/v2.0";
    services.AddSwaggerGen(options =>
    {
        options.SwaggerDoc("v1", new Info
        {
            Title = "My Api Name",
            Version = "v1"
        });

        options.AddSecurityDefinition(OAuth2Definition, new OAuth2Scheme
        {
            Description = "OAuth2 Implicit Grant",
            Flow = "implicit",
            AuthorizationUrl = $"{azureAdAuthority}/authorize",
            TokenUrl = $"{azureAdAuthority}/connect/token",
            Scopes = new Dictionary<string, string>
            {
                {OAuth2Definition, "User.Read"}
            }
        });

        options.AddSecurityRequirement(new Dictionary<string, IEnumerable<string>> {{OAuth2Definition, null}});
    });

    services.AddCors(options => options.AddPolicy("AllowSpecificOrigin", builder => builder
        .WithOrigins(Configuration["MyAppClientUrl"])
        .AllowCredentials()
        .AllowAnyHeader()
        .AllowAnyMethod()
    ));

    // Other Service Registrations.
}

public void Configure(IApplicationBuilder app, IHostingEnvironment env)
{
    app.UseMiddleware<ErrorHandlingMiddleware>();

    app.UseCors("AllowSpecificOrigin");

    app.UseHsts();
    app.UseHttpsRedirection();

    app.UseSwagger();
    app.UseSwaggerUI(config =>
    {
        const string swaggerName = "MyApp Coding Api";
        const string swaggerUrl = "/swagger/v1/swagger.json";

        config.SwaggerEndpoint(swaggerUrl, swaggerName);
        config.RoutePrefix = string.Empty;

        config.OAuthAppName(swaggerName);
        config.OAuthClientId(Configuration["AzureAd:ClientId"]);
        config.OAuthClientSecret(Configuration["AzureAd:ClientSecret"]);
        // This is my Api local path.
        config.OAuthRealm("https://localhost:44398/swagger/ui/o2c-html");
        config.OAuthScopeSeparator(" ");
    });

    app.UseAuthentication();
    app.UseMvc();
}

Ниже представлен токен, сгенерированный клиентом, который отлично работает и реализует .v2.0:

{
  "aud": "{Excldued}",
  "iss": "https://login.microsoftonline.com/{Excldued}/v2.0",
  "iat": 1556730915,
  "nbf": 1556730915,
  "exp": 1556734815,
  "aio": "AVQAq/8LAAAA9lULrpdFyoAfnaWTCkdo8PMz2vL4C0MbDNAxmRBa3rMETsjpnXYFb5izdF/VRWMLzOvwgmw9Zt3zzisWRbLCFMd5KAaJ59wUDqNdSoawS6U = ",
  "name": "{Excldued}",
  "nonce": "{Excldued}",
  "oid": "{Excldued}",
  "preferred_username": "{Excldued}",
  "roles": [
    "Coder",
    "Supervisor"
  ],
  "sub": "Jn0w0rhsGpwTKPdSjQBLHeHDv2_TD4kaOjo0x06JWKQ",
  "tid": "{Excldued}",
  "uti": "pOW4Q_EBdkSv_q0-OHRSAA",
  "ver": "2.0"
}

Но swagger генерирует следующий токен .v1.0:

{
  "aud": "00000003-0000-0000-c000-000000000000",
  "iss": "https://sts.windows.net/{Excluded}/",
  "iat": 1556733552,
  "nbf": 1556733552,
  "exp": 1556737452,
  "acct": 0,
  "acr": "1",
  "aio": "AUQAu/8LAAAA9YXDyeK8KuCHbNgw7RGU8GgJk3qpWB1H+Q3i/dC/VRoAtYvp3NHFIYcTFxn3jfTPvvXRWx5MN35kvO0iCK7ftg= = ",
  "amr": [
    "pwd",
    "mfa"
  ],
  "app_displayname": "{Excluded}",
  "appid": "{Excluded}",
  "appidacr": "0",
  "family_name": "{Excluded}",
  "given_name": "{Excluded}",
  "ipaddr": "{Excluded}",
  "name": "{Excluded}",
  "oid": "{Excluded}",
  "onprem_sid": "{Excluded}",
  "platf": "3",
  "puid": "{Excluded}",
  "scp": "openid profile User.Read email",
  "signin_state": [
    "kmsi"
  ],
  "sub": "{Excluded}",
  "tid": "{Excluded}",
  "unique_name": "{Excluded}",
  "upn": "{Excluded}",
  "uti": "{Excluded}",
  "ver": "1.0",
  "xms_st": {
    "sub": "{Excluded}"
  },
  "xms_tcdt": 1361394419
}

Что я делаю неправильно в своей конфигурации Swagger, которая запрашивает конечную точку 1.0 и получает неправильный тип токена?

ОБНОВИТЬ:

Это запрос скрипача к конечной точке авторизации Azure AD:

GET https://login.microsoftonline.com/{TenantId}/oauth2/v2.0/authorize?response_type=token&client_id = {ClientId}&redirect_uri=https%3A%2F%2Flocalhost%3A44350%2Foauth2-redirect.html&scope=openid&state = {StateValue}&nonce=123456 HTTP/1.1
Host: login.microsoftonline.com
Connection: keep-alive
Upgrade-Insecure-Requests: 1
DNT: 1
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/74.0.3729.157 Safari/537.36
Accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,image/apng,*/*;q=0.8,application/signed-exchange;v=b3
Referer: https://localhost:44350/index.html
Accept-Encoding: gzip, deflate, br
Accept-Language: en-US,en;q=0.9

Привет, Саид, можно ли как-нибудь разместить это локально и получить трассировку скрипача/сети, чтобы увидеть, что на самом деле делает Swagger? И если да, можете ли вы предоставить URL-адрес, на который идет swagger? Похоже, что метод configureservices настроен правильно, поэтому он должен перейти к конечной точке версии 2.0,

Frank H 21.05.2019 02:56

Привет, @FrankHu. Я обновил вопрос с запросом Fiddler. Странно то, что API отлично работает с клиентским SPA-приложением, которое выполняет аутентификацию с помощью библиотеки MSAL. Это просто не работает с Swagger или Postman. Спасибо, что проверили это.

Saeid 21.05.2019 07:48

Если хотите, я могу связать вас со службой технической поддержки для более подробного изучения. Может быть полезно увидеть полную трассировку скрипача. Я не уверен, является ли этот запрос запросом Swagger. Вы можете написать мне по адресу [email protected] и включить в электронное письмо ссылку на эту ветку, чтобы я мог отправить вам бесплатный запрос в службу поддержки.

Frank H 21.05.2019 18:19

@ Саид, как ты это починил?

O.O 27.12.2019 22:53
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
4
4
1 895
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Причина, по которой вы получаете токен версии 1.0, заключается в том, что вы пытаетесь получить доступ к ресурсу версии 1.0. См. статью здесь: https://docs.microsoft.com/en-us/azure/active-directory/develop/access-tokens

Access tokens are created based on the audience of the token, meaning the application that owns the scopes in the token. This is how a resource setting accessTokenAcceptedVersion in the app manifest to 2 allows a client calling the v1.0 endpoint to receive a v2.0 access token. Similarly, this is why changing the access token optional claims for your client do not change the access token received when a token is requested for user.read, which is owned by the MS Graph resource. For the same reason, while testing your client application with a personal account (such as hotmail.com or outlook.com), you may find that the access token received by your client is an opaque string. This is because the resource being accessed has requested legacy MSA (Microsoft account) tickets that are encrypted and can't be understood by the client.

Ваш токен версии 1.0 имеет аудиторию для Microsoft Graph, который выдается конечной точкой версии 1.0. Если вы следите за статьей здесь: https://docs.microsoft.com/en-us/azure/active-directory/develop/v2-oauth2-auth-code-flow Вы увидите, что даже при попадании в конечную точку версии 2.0 и запросе токена доступа с помощью Postman для ресурса graph.microsoft.com вы получите токен доступа, где у iss нет версии 2.0.

Это также очень полезный ресурс, так как это хороший справочник по некоторым популярным идентификаторам GUID в Azure. : https://www.shawntabrizi.com/aad/common-microsoft-resources-azure-active-directory/

Другие вопросы по теме