Вызов функции Azure с авторизацией AD из настольного приложения Windows - PullRequest
0 голосов
/ 16 апреля 2020

ЦЕЛЬ: Я хочу иметь функции Azure (HttpTrigger), которые можно вызывать через настольное приложение Windows. Я хочу, чтобы доступ к функции контролировался Active Directory, и только авторизованные пользователи могли вызывать ее.

ТЕКУЩИЙ СТАТУС: Я следовал инструкции здесь , чтобы создать настольное приложение с авторизацией AD. Я также создал функцию Azure, к которой я добавил «Аутентификацию службы приложений» с «Авторизацией через Azure Active Directory» и создал новую регистрацию приложения для этого. В моем настольном приложении я добавил кнопку, которая вызывает эту функцию.

ПРОБЛЕМА: Когда я вызываю функцию напрямую через ее ссылку в браузере, все работает отлично; если я авторизован, он вызывает функцию, если меня нет, меня перенаправляют на экран входа в систему, и после успешного входа (только для авторизованного пользователя) я получаю результат функции. Проблемы возникают, когда я пытаюсь сделать это через настольное приложение. Когда я нажимаю кнопку вызова функции, меня перенаправляют на экран входа в систему и, как только я успешно захожу с учетными данными, я получаю сообщение об ошибке:

AADSTS50011: The reply URL specified in the request does not match the reply URLs configured for the application: <app-id>

Это происходит, когда при регистрации моего приложения я не иметь опцию аутентификации для «мобильных и настольных приложений», только для «веб». Если я добавлю опцию «Мобильные и настольные приложения», то оригинальная кнопка (из учебного руководства выше) может войти в систему и работать должным образом (в предыдущем случае она выдает ту же ошибку), но на этот раз, когда я пытаюсь вызовите функцию через кнопку, которую я добавил, программа вылетает с ошибками:

Inner Exception 1:
HttpRequestException: An error occurred while sending the request.

Inner Exception 2:
WebException: The underlying connection was closed: An unexpected error occurred on a send.

Inner Exception 3:
IOException: Unable to read data from the transport connection: An existing connection was forcibly closed by the remote host.

Inner Exception 4:
SocketException: An existing connection was forcibly closed by the remote host

Если я принудительно использую TLS 1.2, я получаю ошибку 401: «У вас нет разрешения на просмотр этого каталога или страница. " Если я пытаюсь вызвать функцию, которая не использует авторизацию AD, весь процесс будет успешным. Мой код:

        private async void CallFunctionButton_Click(object sender, RoutedEventArgs e)
        {
            AuthenticationResult authResult = null;
            var app = App.PublicClientApp;
            ResultText.Text = string.Empty;
            TokenInfoText.Text = string.Empty;

            var accounts = await app.GetAccountsAsync();
            var firstAccount = accounts.FirstOrDefault();

            try
            {
                authResult = await app.AcquireTokenSilent(scopes, firstAccount)
                    .ExecuteAsync();
            }
            catch (MsalUiRequiredException ex)
            {
                System.Diagnostics.Debug.WriteLine($"MsalUiRequiredException: {ex.Message}");

                try
                {
                    authResult = await app.AcquireTokenInteractive(scopes)
                        .WithAccount(accounts.FirstOrDefault())
                        .WithParentActivityOrWindow(new WindowInteropHelper(this).Handle)
                        .WithPrompt(Prompt.SelectAccount)
                        .ExecuteAsync();
                }
                catch (MsalException msalex)
                {
                    ResultText.Text = $"Error Acquiring Token:{System.Environment.NewLine}{msalex}";
                }
            }
            catch (Exception ex)
            {
                ResultText.Text = $"Error Acquiring Token Silently:{System.Environment.NewLine}{ex}";
                return;
            }

            if (authResult != null)
            {
                this.SignOutButton.Visibility = Visibility.Visible;
                string token = authResult.AccessToken;

                using (var client = new HttpClient())
                {
                    // With an explicit selection of the security protocol the program does not crash.
                    // Instead it gives 401 Unauthorized error, when already signed in.
                    // Without the following line, the program crashes.
                    ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;


                    string requestUrl = $"the_URL_of_my_function";

                    HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, requestUrl);
                    request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", token);

                    HttpResponseMessage response = client.SendAsync(request).Result;
                    var responseString = response.Content.ReadAsStringAsync().Result;
                    ResultText.Text = responseString;
                    DisplayBasicTokenInfo(authResult);
                }
            }
        }

ВОПРОС: Можно ли вызвать / использовать функцию Azure, для которой требуется авторизация через настольное приложение Windows и как?

1 Ответ

1 голос
/ 17 апреля 2020

Относительно проблемы, это может относиться к версии TLS. Насколько я знаю, на данный момент Azure Служба приложений будет создана с TLS 1.2 по умолчанию . Но приложение WPF по умолчанию использует TLS 1.0. Поэтому мы не можем вызвать функцию Azure. Относительно того, как это исправить, обратитесь к документу


Обновление

Относительно того, как вызывать функцию Azure, спроецированную Azure AD, пожалуйста, см. следующие шаги

  1. Настройка Azure AD для Azure Функция enter image description here

  2. Создание клиентское приложение в Azure AD

  3. Настройка разрешений API и получение области действия. nedd enter image description here enter image description here

  4. код

string[] scopes = new string[] 
{"https://testfun08.azurewebsites.net/user_impersonation" };// the scope you copy

 private async void CallFunctionButton_Click(object sender, RoutedEventArgs e)
        {
      // get token
          AuthenticationResult authResult = null;
            var app = App.PublicClientApp;
            ResultText.Text = string.Empty;
            TokenInfoText.Text = string.Empty;

            var accounts = await app.GetAccountsAsync();
            var firstAccount = accounts.FirstOrDefault();

            try
            {
                authResult = await app.AcquireTokenSilent(scopes, firstAccount)
                    .ExecuteAsync();
            }
            catch (MsalUiRequiredException ex)
            {
                System.Diagnostics.Debug.WriteLine($"MsalUiRequiredException: {ex.Message}");

                try
                {
                    authResult = await app.AcquireTokenInteractive(scopes)
                        .WithAccount(accounts.FirstOrDefault())
                        .WithParentActivityOrWindow(new WindowInteropHelper(this).Handle)
                        .WithPrompt(Prompt.SelectAccount)
                        .ExecuteAsync();
                }
                catch (MsalException msalex)
                {
                    ResultText.Text = $"Error Acquiring Token:{System.Environment.NewLine}{msalex}";
                }
            }
            catch (Exception ex)
            {
                ResultText.Text = $"Error Acquiring Token Silently:{System.Environment.NewLine}{ex}";
                return;
            }

       //call Azure function
            if (authResult != null)
            {
                this.SignOutButton.Visibility = Visibility.Visible;
                string token = authResult.AccessToken;

                using (var client = new HttpClient())
                {
                    // Without the following line, the program crashes.
                    ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls12;


                    string requestUrl = $"the_URL_of_my_function";
                 client.DefaultRequestHeaders.Add("Authorization", "Bearer " + token);
                    HttpRequestMessage request = new HttpRequestMessage(HttpMethod.Get, requestUrl);


                    HttpResponseMessage response = client.SendAsync(request).Result;
                    var responseString = response.Content.ReadAsStringAsync().Result;
                    ResultText.Text = responseString;
                    DisplayBasicTokenInfo(authResult);
                }
            }
        }

enter image description here

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...