Проверка подлинности в службе Azure SignalR

В этом руководстве продолжается работа с приложением комнаты чата, представленным в статье "Создание комнаты чата со службой SignalR". Сначала выполните это краткое руководство, чтобы настроить комнату чата.

В этом руководстве вы узнаете, как создать и интегрировать свой метод аутентификации с использованием службы Microsoft Azure SignalR.

Изначально используемая аутентификация в приложении для чата из руководства по быстрому старту слишком простая для реальных сценариев. Приложение позволяет каждому клиенту утверждать то, кем он является и сервер это просто принимает. Этот подход неэффективн в реальном мире, так как злоумышленники могут использовать поддельные удостоверения для доступа к конфиденциальным данным.

Портал GitHub предоставляет API аутентификацию, основанную на популярном протоколе отраслевого стандарта OAuth. Эти API-интерфейсы позволяют сторонним приложениям аутентифицировать учетные записи GitHub. В этом руководстве вы можете использовать эти API для реализации проверки подлинности с помощью учетной записи GitHub перед разрешением входа клиента в приложение комнаты чата. После проверки подлинности учетной записи GitHub сведения об учетной записи будут добавлены в виде файла cookie, который будет использоваться веб-клиентом для проверки подлинности.

Дополнительные сведения о API аутентификации OAuth, предоставленной через GitHub, см. в статье Basics of Authentication (Основы аутентификации).

Вы можете использовать любой редактор кода для выполнения шагов в этом кратком руководстве. Однако Visual Studio Code является отличным вариантом, доступным на платформах Windows, MacOS и Linux.

Код для этого руководства доступен для скачивания в репозитории примеров AzureSignalR на GitHub.

Полная реализация OAuth в Azure

В этом руководстве описано следующее:

  • Зарегистрируйте новое приложение OAuth в своей учетной записи GitHub.
  • Добавить контроллер аутентификации для поддержки аутентификации через GitHub
  • Развертывать веб приложение ASP.NET Core в Azure

Если у вас нет аккаунта Azure, создайте бесплатную учетную запись перед началом.

Предварительные условия

Для работы с этим руководством необходимо следующее:

Создание приложения OAuth

  1. Откройте веб-браузер, перейдите к https://github.com и войдите в свою учетную запись.

  2. Для вашей учетной записи перейдите в Настройки>Настройки разработчика>Приложения OAuth и выберите Создать новое приложение OAuth в категории Приложения OAuth.

  3. Используйте следующие настройки для нового приложения OAuth, затем выберите Зарегистрировать приложение.

    Имя параметра Рекомендуемое значение Описание
    Имя приложения Azure SignalR Чат Пользователь GitHub должен иметь возможность распознавать и доверять приложению, с которым они выполняют проверку подлинности.
    URL-адрес домашней страницы https://localhost:5001
    Описание приложения Пример использования службы Azure SignalR в комнате чата с помощью аутентификации GitHub Полезное описание приложения, которое помогает пользователям приложения понять контекст используемой проверки подлинности.
    URL-адрес обратного вызова авторизации https://localhost:5001/signin-github Этот параметр является самым важным параметром для приложения OAuth. Он является URL-адресом обратного вызова, который GitHub возвращает пользователю, после успешной аутентификации. В этом руководстве по умолчанию необходимо использовать URL-адрес обратного вызова для пакета AspNet.Security.OAuth.GitHub, /signin-github.
  4. После завершения регистрации нового приложения OAuth добавьте Идентификатор клиента и Секрет клиента в менеджер секретов с помощью следующих команд. Замените Your_GitHub_Client_Id и Your_GitHub_Client_Secret на значения из собственного приложения OAuth.

    dotnet user-secrets set GitHubClientId Your_GitHub_Client_Id
    dotnet user-secrets set GitHubClientSecret Your_GitHub_Client_Secret
    

Реализация потока OAuth

Давайте снова используем приложение чата, созданное в учебнике Создание комнаты чата с использованием службы SignalR.

Обновить Program.cs для поддержки аутентификации GitHub

  1. Добавьте ссылку на последние пакеты AspNet.Security.OAuth.GitHub и восстановите все пакеты.

    dotnet add package AspNet.Security.OAuth.GitHub
    
  2. Откройте Program.cs и обновите код до следующего фрагмента кода:

    using Microsoft.AspNetCore.Authentication.Cookies;
    using Microsoft.AspNetCore.Authentication.OAuth;
    
    using System.Net.Http.Headers;
    using System.Security.Claims;
    
    var builder = WebApplication.CreateBuilder(args);
    
    builder.Services
        .AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
        .AddCookie()
        .AddGitHub(options =>
        {
            options.ClientId = builder.Configuration["GitHubClientId"] ?? "";
            options.ClientSecret = builder.Configuration["GitHubClientSecret"] ?? "";
            options.Scope.Add("user:email");
            options.Events = new OAuthEvents
            {
                OnCreatingTicket = GetUserCompanyInfoAsync
            };
        });
    
    builder.Services.AddControllers();
    builder.Services.AddSignalR().AddAzureSignalR();
    
    var app = builder.Build();
    
    app.UseHttpsRedirection();
    app.UseDefaultFiles();
    app.UseStaticFiles();
    
    app.UseRouting();
    
    app.UseAuthorization();
    
    app.MapControllers();
    app.MapHub<ChatSampleHub>("/chat");
    
    app.Run();
    
    static async Task GetUserCompanyInfoAsync(OAuthCreatingTicketContext context)
    {
        var request = new HttpRequestMessage(HttpMethod.Get, context.Options.UserInformationEndpoint);
        request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
        request.Headers.Authorization = new AuthenticationHeaderValue("Bearer", context.AccessToken);
    
        var response = await context.Backchannel.SendAsync(request,
            HttpCompletionOption.ResponseHeadersRead, context.HttpContext.RequestAborted);
        var user = await response.Content.ReadFromJsonAsync<GitHubUser>();
        if (user?.company != null)
        {
            context.Principal?.AddIdentity(new ClaimsIdentity(new[]
            {
                new Claim("Company", user.company)
            }));
        }
    }
    
    class GitHubUser
    {
        public string? company { get; set; }
    }
    

    В коде AddAuthentication и UseAuthentication используются для добавления поддержки проверки подлинности с помощью приложения OAuth GitHub, а GetUserCompanyInfoAsync вспомогательный метод — это пример кода, показывающий, как загрузить сведения компании из GitHub OAuth и сохранить его в удостоверение пользователя. Вы также можете заметить, что UseHttpsRedirection() используется, так как GitHub OAuth устанавливает secure cookie-файл, который проходит только через защищённую https схему. Кроме того, не забудьте обновить локальный Properties/launchSettings.json , чтобы добавить конечную точку https:

    {
      "profiles": {
        "GitHubChat" : {
          "commandName": "Project",
          "launchBrowser": true,
          "environmentVariables": {
            "ASPNETCORE_ENVIRONMENT": "Development"
          },
          "applicationUrl": "http://0.0.0.0:5000/;https://0.0.0.0:5001/;"
        }
      }
    }
    

Добавление контроллера проверки подлинности

В этом разделе вы реализуете Login API, который аутентифицирует клиентов с помощью приложения OAuth GitHub. После проверки подлинности API добавляет файл cookie в ответ веб-клиента перед перенаправлением клиента обратно в приложение чата. Затем этот файл cookie используется для идентификации клиента.

  1. Добавьте новый файл кода контроллера в каталог GitHubChat\Controllers . Назовите файл AuthController.cs.

  2. Добавьте следующий код для контроллера аутентификации. Обязательно обновите пространство имен, если каталог вашего проекта отличается от GitHubChat:

    using AspNet.Security.OAuth.GitHub;
    
    using Microsoft.AspNetCore.Authentication;
    using Microsoft.AspNetCore.Mvc;
    
    namespace GitHubChat.Controllers
    {
        [Route("/")]
        public class AuthController : Controller
        {
            [HttpGet("login")]
            public IActionResult Login()
            {
                if (User.Identity == null || !User.Identity.IsAuthenticated)
                {
                    return Challenge(GitHubAuthenticationDefaults.AuthenticationScheme);
                }
    
                HttpContext.Response.Cookies.Append("githubchat_username", User.Identity.Name ?? "");
                HttpContext.SignInAsync(User);
                return Redirect("/");
            }
        }
    }
    
  3. Сохраните изменения.

Обновление класса Hub

По умолчанию веб-клиент подключается к Службе SignalR с помощью маркера доступа, автоматически созданного SDK Azure SignalR.

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

  1. Откройте Hub\ChatSampleHub.cs и обновите код до приведенного ниже фрагмента кода. Код добавляет атрибут Authorize к классу ChatSampleHub и использует удостоверение пользователя, проверенного на подлинность, в методах концентратора. Кроме того, добавлен метод OnConnectedAsync, который логирует системное сообщение в комнату чата при каждом подключении нового клиента.

    using Microsoft.AspNetCore.Authorization;
    using Microsoft.AspNetCore.SignalR;
    
    [Authorize]
    public class ChatSampleHub : Hub
    {
        public override Task OnConnectedAsync()
        {
            return Clients.All.SendAsync("broadcastMessage", "_SYSTEM_", $"{Context.User?.Identity?.Name} JOINED");
        }
    
        // Uncomment this line to only allow user in Microsoft to send message
        //[Authorize(Policy = "Microsoft_Only")]
        public Task BroadcastMessage(string message)
        {
            return Clients.All.SendAsync("broadcastMessage", Context.User?.Identity?.Name, message);
        }
    
        public Task Echo(string message)
        {
            var echoMessage = $"{message} (echo from server)";
            return Clients.Client(Context.ConnectionId).SendAsync("echo", Context.User?.Identity?.Name, echoMessage);
        }
    }
    
  2. Сохраните изменения.

Обновление кода веб-клиента

  1. Откройте файл wwwroot\index.html и замените код, который предлагает ввести имя пользователя на код, который использует файл cookie, возвращенный контролером аутентификации.

    Обновите код внутри функции getUserName в index.html следующим образом, чтобы использовать файлы cookie:

    function getUserName() {
      // Get the user name cookie.
      function getCookie(key) {
        var cookies = document.cookie.split(";").map((c) => c.trim());
        for (var i = 0; i < cookies.length; i++) {
          if (cookies[i].startsWith(key + "="))
            return unescape(cookies[i].slice(key.length + 1));
        }
        return "";
      }
      return getCookie("githubchat_username");
    }
    
  2. Обновите функцию onConnected для удаления параметра username при вызове метода концентратора broadcastMessage и echo.

    function onConnected(connection) {
      console.log("connection started");
      connection.send("broadcastMessage", "_SYSTEM_", username + " JOINED");
      document.getElementById("sendmessage").addEventListener("click", function (event) {
        // Call the broadcastMessage method on the hub.
        if (messageInput.value) {
          connection.invoke("broadcastMessage", messageInput.value)
            .catch((e) => appendMessage("_BROADCAST_", e.message));
        }
    
        // Clear text box and reset focus for next comment.
        messageInput.value = "";
        messageInput.focus();
        event.preventDefault();
      });
      document.getElementById("message").addEventListener("keypress", function (event) {
        if (event.keyCode === 13) {
          event.preventDefault();
          document.getElementById("sendmessage").click();
          return false;
        }
      });
      document.getElementById("echo").addEventListener("click", function (event) {
        // Call the echo method on the hub.
        connection.send("echo", messageInput.value);
    
        // Clear text box and reset focus for next comment.
        messageInput.value = "";
        messageInput.focus();
        event.preventDefault();
      });
    }
    
  3. В нижней части index.html обновите обработчик ошибок connection.start(), чтобы пользователю предлагалось войти, как показано ниже.

    connection.start()
      .then(function () {
        onConnected(connection);
      })
      .catch(function (error) {
        console.error(error.message);
        if (error.statusCode && error.statusCode === 401) {
          appendMessage(
            "_BROADCAST_",
            "You\"re not logged in. Click <a href="/login">here</a> to login with GitHub."
          );
        }
      });
    
  4. Сохраните изменения.

Локальное создание и запуск приложения

  1. Сохраните изменения для всех файлов.

  2. Выполните следующую команду, чтобы запустить веб-приложение локально:

    dotnet run
    

    Приложение размещается локально на порту 5000 по умолчанию:

    info: Microsoft.Hosting.Lifetime[14]
          Now listening on: http://0.0.0.0:5000
    info: Microsoft.Hosting.Lifetime[14]
          Now listening on: https://0.0.0.0:5001
    info: Microsoft.Hosting.Lifetime[0]
          Application started. Press Ctrl+C to shut down.
    info: Microsoft.Hosting.Lifetime[0]
          Hosting environment: Development
    
  3. Запустите окно браузера и перейдите по адресу https://localhost:5001. Выберите здесь ссылку в верхней части, чтобы войти в систему с помощью GitHub.

    Полная реализация OAuth в Azure

    Вам будет предложено авторизовать доступ приложения чата к учетной записи GitHub. Нажмите кнопку Авторизовать.

    Авторизация приложения OAuth

    Вы перенаправляетесь обратно в приложение чата и вошли в систему с именем учетной записи GitHub. Веб-приложение определило имя вашей учетной записи, аутентифицируя вас с использованием нового метода, который вы добавили.

    Обнаружение учетной записи

    При использовании приложения чата теперь выполняется проверка подлинности с помощью GitHub и хранятся сведения проверки подлинности в виде файлов cookie, на следующем шаге предполагается развертывание в Azure. Этот подход позволяет другим пользователям проходить проверку подлинности с помощью соответствующих учетных записей и обмениваться данными с различных рабочих станций.

Развертывание приложения в Azure

Подготовьте среду к работе с Azure CLI:

В этом разделе вы используете Azure CLI для создания нового веб-приложения в Azure App Service для размещения вашего ASP.NET приложения в Azure. Веб-приложение настроено для использования локального развертывания Git. Веб-приложение также настроено с строкой подключения для SignalR, секретами OAuth приложения GitHub и пользователем для развертывания.

При создании следующего ресурса, обязательно используйте ту же группу ресурсов, в которой находится ресурс службы SignalR. Этот подход упрощает очистку позже, когда вы хотите удалить все ресурсы. В приведенном примере предполагается использование имени группы SignalRTestResources, рекомендованного в предыдущих руководствах.

Создание веб-приложения и плана

Скопируйте текст для команд, приведенных ниже, и обновите параметры. Вставьте обновленный сценарий в Azure Cloud Shell и нажмите клавишу ВВОД, чтобы создать новый план службы приложений и веб-приложений.

#========================================================================
#=== Update these variable for your resource group name.              ===
#========================================================================
ResourceGroupName=SignalRTestResources

#========================================================================
#=== Update these variable for your web app.                          ===
#========================================================================
WebAppName=myWebAppName
WebAppPlan=myAppServicePlanName

# Create an App Service plan.
az appservice plan create --name $WebAppPlan --resource-group $ResourceGroupName \
    --sku FREE

# Create the new Web App
az webapp create --name $WebAppName --resource-group $ResourceGroupName \
    --plan $WebAppPlan
Параметр Описание
ИмяГруппыРесурсов Это имя группы ресурсов было предложено в предыдущих руководствах. Рекомендуется группировать все учебные ресурсы вместе. Используйте ту же группу ресурсов, что и в предыдущих руководствах.
WebAppPlan Введите новое, уникальное имя плана служб приложений.
WebAppName Этот параметр является именем нового веб-приложения и частью URL-адреса. Сделайте его уникальным. Например, signalrtestwebapp22665120.

Добавление параметров приложения к веб-приложению

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

  • Строка подключения ресурса службы SignalR
  • Идентификатор клиента приложения OAuth GitHub
  • Секрет клиента приложения OAuth GitHub

Скопируйте текст для команд, приведенных ниже, и обновите параметры. Вставьте обновленный сценарий в Azure Cloud Shell и нажмите клавишу ВВОД, чтобы добавить параметры приложения.

#========================================================================
#=== Update these variables for your GitHub OAuth App.                ===
#========================================================================
GitHubClientId=1234567890
GitHubClientSecret=1234567890

#========================================================================
#=== Update these variables for your resources.                       ===
#========================================================================
ResourceGroupName=SignalRTestResources
SignalRServiceResource=mySignalRresourcename
WebAppName=myWebAppName

# Get the SignalR primary connection string
primaryConnectionString=$(az signalr key list --name $SignalRServiceResource \
  --resource-group $ResourceGroupName --query primaryConnectionString -o tsv)

#Add an app setting to the web app for the SignalR connection
az webapp config appsettings set --name $WebAppName \
    --resource-group $ResourceGroupName \
    --settings "Azure__SignalR__ConnectionString=$primaryConnectionString"

#Add the app settings to use with GitHub authentication
az webapp config appsettings set --name $WebAppName \
    --resource-group $ResourceGroupName \
    --settings "GitHubClientId=$GitHubClientId"
az webapp config appsettings set --name $WebAppName \
    --resource-group $ResourceGroupName \
    --settings "GitHubClientSecret=$GitHubClientSecret"
Параметр Описание
GitHubClientId Назначьте этой переменной секретный идентификатор клиента для вашего GitHub-приложения OAuth.
GitHubClientSecret Назначьте этой переменной секретный пароль для приложения OAuth GitHub.
ИмяГруппыРесурсов Обновите эту переменную, чтобы у нее было то же имя, что и у группы ресурсов, которую вы использовали в предыдущем разделе.
Ресурс службы SignalR Обновите эту переменную, указав имя ресурса SignalR, который вы создали в быстром старте. Например, signalrtestsvc48778624.
WebAppName Обновите эту переменную, чтобы у нее было то же имя, что и у нового веб-приложения, которое вы создали в предыдущем разделе.

Настройка веб-приложения для локального развертывания Git

Вставьте следующий сценарий в Azure Cloud Shell. Этот скрипт создает новое имя пользователя развертывания и пароль, которые вы используете при развертывании кода в веб-приложении с помощью Git. Сценарий также настраивает веб-приложение для развертывания с помощью локального репозитория Git и возвращает URL-адрес развертывания Git.

#========================================================================
#=== Update these variables for your resources.                       ===
#========================================================================
ResourceGroupName=SignalRTestResources
WebAppName=myWebAppName

#========================================================================
#=== Update these variables for your deployment user.                 ===
#========================================================================
DeploymentUserName=myUserName
DeploymentUserPassword=myPassword

# Add the desired deployment user name and password
az webapp deployment user set --user-name $DeploymentUserName \
    --password $DeploymentUserPassword

# Configure Git deployment and note the deployment URL in the output
az webapp deployment source config-local-git --name $WebAppName \
    --resource-group $ResourceGroupName \
    --query [url] -o tsv
Параметр Описание
ИмяПользователяРазвертывания Выберите новое имя пользователя для развертывания.
ПарольПользователяРазвертывания Выберите пароль для нового пользователя для развертывания.
ИмяГруппыРесурсов Используйте имя группы ресурсов, которое соответствует имени группы ресурсов, использованному в предыдущем разделе.
WebAppName Этот параметр — это имя созданного ранее веб-приложения.

Запишите URL-адрес развертывания Git, возвращенный из этой команды. Вы используете этот URL позже.

Разверните код в веб-приложении Azure

Выполните следующую команду в Git Shell, чтобы развернуть код.

  1. Перейдите в корневой каталог проекта. Если у вас нет проекта, инициализированного с помощью репозитория Git, выполните следующую команду:

    git init
    
  2. Добавьте remote для URL-адреса развертывания Git, записанного ранее.

    git remote add Azure <your git deployment url>
    
  3. Добавьте все файлы в индекс инициализированного репозитория и выполните коммит.

    git add -A
    git commit -m "init commit"
    
  4. Разверните ваш код в веб-приложении, работающем на платформе Azure.

    git push Azure main
    

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

Обновление приложения OAuth GitHub

И наконец, для завершения процесса выполните обновление URL-адреса домашней страницы и URL-адреса обратного вызова авторизации приложения OAuth GitHub, чтобы указать новое размещенное приложение.

  1. В браузере откройте https://github.com и в учетной записи перейдите в Параметры>Параметры разработчика>OAuth Apps.

  2. Выберите приложение проверки подлинности и обновите URL-адрес домашней страницы и URL-адрес обратного вызова авторизации, как показано ниже:

    Настройка Пример
    URL-адрес домашней страницы https://signalrtestwebapp22665120.azurewebsites.net
    URL-адрес обратного вызова авторизации https://signalrtestwebapp22665120.azurewebsites.net/signin-github
  3. Перейдите к URL-адресу веб-приложения и протестируйте приложение.

    Полная реализация OAuth в Azure

Очистка ресурсов

Если вы продолжите работу со следующим руководством, вы можете сохранить ресурсы, созданные в этом кратком руководстве, и повторно использовать их с помощью следующего руководства.

В противном случае, если вы закончили работу с quickstart-примером приложения, вы можете удалить ресурсы Azure, созданные в этом кратком руководстве, чтобы избежать расходов.

Внимание

Удаление группы ресурсов — необратимая операция, и все соответствующие ресурсы удаляются окончательно. Будьте внимательны, чтобы случайно не удалить не ту группу ресурсов или не те ресурсы. Если вы создали ресурсы для размещения этого примера в уже существующей группе ресурсов, которая содержит ресурсы, которые вы хотите сохранить, вы можете удалить каждый ресурс по отдельности на их соответствующих вкладках вместо удаления всей группы ресурсов.

Войдите в портал Azure и выберитеГруппы ресурсов.

Введите имя группы ресурсов в текстовое поле Фильтровать по имени.... В инструкциях в этой статье использовалась группа ресурсов с именем SignalRTestResources. В своей группе ресурсов в списке результатов щелкните ..., а затем Удалить группу ресурсов.

Удаление

Подтвердите операцию удаления группы ресурсов. Введите имя группы ресурсов, которую необходимо удалить, и нажмите Удалить.

Через некоторое время группа ресурсов и все ее ресурсы будут удалены.

Следующие шаги

В этом руководстве вы научились добавлять аутентификацию с помощью OAuth, чтобы улучшить подход к аутентификации службы Azure SignalR. Чтобы узнать больше об использовании сервера Azure SignalR, перейдите к примерам Azure CLI для службы SignalR.