«Для этого запроса было отказано в авторизации» при локальном размещении серверной части службы приложений Azure в IIS - PullRequest
1 голос
/ 08 марта 2019

В моем бэкэнде службы приложений Azure .NET я обычно украшаю свои контроллеры с помощью [authorize], чтобы они были защищены от пользователей, которые не вошли в систему. Для аутентификации пользователя я настроил клиента Azure Active Directory B2C (AADB2C),настроил приложение, а также некоторых поставщиков удостоверений, и все работает как положено, пока я размещаю свой бэкэнд в Azure.

Теперь я хотел бы иметь возможность запускать бэкэнд локально, чтобы я мог легкоотладить код и заставить его работать с локальной базой данных разработки.

Однако это не работает.

  • Я перешел на https://[myappservice].scm.azurewebsites.net/ и получил WEBSITE_AUTH_SIGNING_KEY на вкладке среды.
  • Я добавил ключ к web.config моего бэкэнда как Signingkey в AppSettings
  • Я изменил ValidAudience и ValidIssuer на соответствующие значения(https://[myappservice].azurewebsites.net)
  • Чтобы я мог связать бэкэнд с IP-адресом или именем моего хоста, а не с «localhost» (как в случае с IIS Express), я настроил бэкэнд для работы под IIS
  • Я разрешил анонимный доступ только на своем веб-сайте IIS и позволил ему работать под DefaultAppPool, который использует интегрированный конвейер на 4.0 CLR

Мой код клиента не использует MobileServiceClient, но MSAL (PublicClientApplicationТаким образом, документация о том, как настроить локальную среду разработки, найденную здесь , не применима.

Поскольку у меня есть класс RequestProvider, который создает необходимый HttpClи добавляет токен доступа в заголовок, это не должно быть проблемой, потому что для аутентификации объект PublicClientApplication использует клиента AADB2C и соответствующие политики потоков сервера для входа в систему и -up, а также для вызова контроллера покоя бэкэнда Iможет переключаться между хостом Azure и локально размещенным бэкэндом.

Однако, хотя аутентификация продолжает работать как чудо, и я могу получить рабочий токен доступа, бэкэнд, размещенный локально, не принимает его, покатот же бэкэнд-код, размещенный на Azure.

Итак, я начал искать в сети и узнал о сайте jwt.io .Я вставил свой токен доступа в их декодер и был удивлен результатом.

В некоторых статьях упоминалось, что значения ValidIssuer и ValidAudience настроены в web.config бэкэндовнеобходимо точно отражать значения iss и aud , содержащиеся в маркере доступа.

Однако значения в my token access не совпадаютхотя схема, которая была частью шаблона web.config (https://[myappservice].azurewebsites.net).

Поле iss в my декодированном токене, выглядело так:

https://[myappservice].b2clogin.com/12345678-1234-1234-1234-123456789012/v2.0/

Поле aud в my декодированном токене выглядело так:

12345678-1234-1234-1234-123456789012

Значение isser можно найти в моих AADb2C арендаторахкаталог в настройках политики входа / -up в Свойствах в «Настройках совместимости токенов» от имени Заявка эмитента (iss) .которого выбрано следующее значение:

https://<domain>/12345678-1234-1234-1234-123456789012/v2.0/

aud guid полей равен идентификатору клиента , настроенному в службе приложений в Azure.

Однако, даже если я возьму эти два значения и введу их в web.configкак описано выше, я все еще получаю сообщение об ошибке «Отказано в авторизации для этого запроса».

Я действительно не знаю, как заставить это работать ...

1 Ответ

0 голосов
/ 14 марта 2019

Я попытался воспроизвести вашу проблему, и она работает хорошо, если в моей среде.Я имел в виду active-directory-b2c-dotnet-desktop как собственный клиент и active-directory-b2c-dotnet-webapp-and-webapi (размещение проекта API на IIS,проект веб-приложения не используется) в качестве бэкэнда API.

Я также несколько раз сталкивался с такой же проблемой при тестировании и решил ее, выполнив следующие действия:

  • Нет специальныхКонфигурация требуется на стороне IIS.Вам не нужно указывать «Ключ подписи» в web.congig, потому что при проверке токена ключ подписи будет автоматически выбираться из конечной точки metedata (поле jwks_uri):

    https://TenantName.b2clogin.com/TenantName.onmicrosoft.com/v2.0/.well-known/openid-configuration?p=SignInPolicyName

  • На портале Azure убедитесь, что вы предоставили нативному клиенту доступ к приложению API.enter image description here

Для другой базовой конфигурации обратитесь к инструкции примеров выше.

Я также предлагаю вам декодировать токен доступа и подтвердитьосновные утверждения верны:

  1. "iss" должен совпадать с экземпляром AAD в приложении API
  2. "aud" должен быть идентификатором клиента
  3. "sub"или «oid» должно быть идентификатором объекта вошедшего в систему пользователя.
  4. «tfp» должно быть знаком имени политики
  5. «scp» должно быть опубликовано в области приложения API

Другие утверждения см. В Azure AD B2C: ссылка на токен

Обратите внимание, что в приведенных выше официальных примерах все еще используется login.microsoftonline.com в качестве конечной точки доступа.b2clogin.com.Чтобы использовать b2clogin, просто обновите конечную точку соответственно.

Ниже приведен фрагмент кода и настройки в моем рабочем примере:

Собственный клиент

public partial class App : Application
{
    private static string TenantName = "<TenantName>";
    private static string Tenant = "<TenantName>.onmicrosoft.com";
    private static string ClientId = "<ClientID>";
    public static string PolicySignUpSignIn = "B2C_1_signupsignin1";
    public static string PolicyEditProfile = "b2c_1_edit";
    public static string PolicyResetPassword = "b2c_1_reset";

    public static string[] ApiScopes = { "https://<TenantName>.onmicrosoft.com/demoapi/demo.read" };
    public static string ApiEndpoint = "http://<IISServerAddress>/taskservice/api/tasks";

    private static string BaseAuthority = "https://login.microsoftonline.com/tfp/{tenant}/{policy}/oauth2/v2.0/authorize";
    private static string BaseAuthorityForb2clogin = "https://{TenantName}.b2clogin.com/tfp/{tenant}/{policy}";
    public static string Authority = BaseAuthorityForb2clogin.Replace("{tenant}", Tenant).Replace("{policy}", PolicySignUpSignIn).Replace("{TenantName}", TenantName);

    public static PublicClientApplication PublicClientApp { get; } = new PublicClientApplication(ClientId, Authority, TokenCacheHelper.GetUserCache());
}

Конфигурация приложения API:

<add key="ida:AadInstance" value="https://tomtestb2c.b2clogin.com/{0}/v2.0/.well-known/openid-configuration?p={1}" />
<add key="ida:Tenant" value="TenantName.onmicrosoft.com" />
<add key="ida:ClientId" value="ClientId-ff8e-4ac2-a093-6c6e0f8e116c" />
<add key="ida:SignUpSignInPolicyId" value="B2C_1_signupsignin1" />
<!-- The following settings is used for requesting access tokens -->
<add key="api:ReadScope" value="read" />
<add key="api:WriteScope" value="write" />

Authкод:

public partial class Startup
{
    // These values are pulled from web.config
    public static string AadInstance = ConfigurationManager.AppSettings["ida:AadInstance"];
    public static string Tenant = ConfigurationManager.AppSettings["ida:Tenant"];
    public static string ClientId = ConfigurationManager.AppSettings["ida:ClientId"];
    public static string SignUpSignInPolicy = ConfigurationManager.AppSettings["ida:SignUpSignInPolicyId"];
    public static string DefaultPolicy = SignUpSignInPolicy;

    /*
     * Configure the authorization OWIN middleware 
     */
    public void ConfigureAuth(IAppBuilder app)
    {
        TokenValidationParameters tvps = new TokenValidationParameters
        {
            // Accept only those tokens where the audience of the token is equal to the client ID of this app
            ValidAudience = ClientId,
            AuthenticationType = Startup.DefaultPolicy
        };

        app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions
        {
            // This SecurityTokenProvider fetches the Azure AD B2C metadata & signing keys from the OpenIDConnect metadata endpoint
            AccessTokenFormat = new JwtFormat(tvps, new OpenIdConnectCachingSecurityTokenProvider(String.Format(AadInstance, Tenant, DefaultPolicy)))
        });
    }
}
...