Azure SignalR 服務驗證

本教學課程會繼續進行使用 SignalR Service 建立聊天室中介紹的聊天室應用程式。 請先完成該快速入門,以設定聊天室。

在本教學課程中,瞭解如何使用 Microsoft Azure SignalR Service 建立及整合您的驗證方法。

最初在快速入門聊天室應用程式中使用的驗證對於真實世界案例來說太簡單了。 應用程式可讓每個用戶端宣告其身分,而伺服器則只接受。 這種方法在真實世界中無效,因為惡意使用者可以使用假身分識別來存取敏感數據。

GitHub 會根據稱為 OAuth 的熱門業界標準通訊協定來提供驗證 API。 這些 API 可讓第三方應用程式驗證 GitHub 帳戶。 在本教學課程中,您可以使用這些 API 透過 GitHub 帳戶實作驗證,再允許用戶端登入聊天室應用程式。 GitHub 帳戶驗證之後,帳戶資訊將會新增為 Web 用戶端用來驗證的 Cookie。

如需透過 GitHub 提供的 OAuth 驗證 API 的詳細資訊,請參閱 驗證的基本概念。

您可以使用任何程式代碼編輯器來完成本快速入門中的步驟。 不過, Visual Studio Code 是 Windows、macOS 和 Linux 平臺上的絕佳選項。

本教學課程的程式代碼可在 AzureSignalR-samples GitHub 存放庫中下載

OAuth Complete hosted in Azure

在本教學課程中,您會了解如何:

  • 向 GitHub 帳戶註冊新的 OAuth 應用程式
  • 新增驗證控制器以支援 GitHub 驗證
  • 將 ASP.NET Core Web 應用程式部署至 Azure

如果您沒有 Azure 訂閱,請在開始之前,先建立 Azure 免費帳戶

必要條件

若要完成本教學課程,您必須具備下列必要條件:

建立 OAuth 應用程式

  1. 開啟網頁瀏覽器,並流覽至 https://github.com 並登入您的帳戶。

  2. 針對您的帳戶,流覽至 [設定> 開發人員設定>OAuth Apps],然後選取 [OAuth Apps] 底下的 [新增 OAuth 應用程式]。

  3. 針對新的 OAuth 應用程式使用下列設定,然後選取 [ 註冊應用程式]:

    設定名稱 建議的值 描述
    應用程式名稱 Azure SignalR Chat GitHub 使用者應該能夠辨識並信任他們正在驗證的應用程式。
    首頁 URL https://localhost:5001
    應用程式描述 使用 Azure SignalR Service 搭配 GitHub 驗證的聊天室範例 應用程式的實用描述,可協助應用程式使用者瞭解所使用的驗證內容。
    授權回呼 URL https://localhost:5001/signin-github 此設定是 OAuth 應用程式最重要的設定。 這是 GitHub 在成功驗證之後將用戶傳回的回呼 URL。 在本教學課程中,您必須使用 AspNet.Security.OAuth.GitHub 套件 /signin-github 的預設回呼 URL
  4. 完成新的 OAuth 應用程式註冊之後,請使用下列命令,將 用戶端標識碼客戶端密碼 新增至秘密管理員。 將 Your_GitHub_Client_IdYour_GitHub_Client_Secret 取代為 OAuth 應用程式的值。

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

實作 OAuth 流程

讓我們重複使用使用 SignalR Service 建立聊天室教學課程中建立的聊天應用程式。

更新 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 用來新增 GitHub OAuth 應用程式的驗證支援,而 GetUserCompanyInfoAsync 協助程式方法是範例程式代碼,示範如何從 GitHub OAuth 載入公司資訊並儲存至使用者身分識別。 您可能也會注意到, UseHttpsRedirection() 因為 GitHub OAuth 設定 secure Cookie 只會傳遞至安全 https 配置,因此會使用 。 也別忘了更新本機 Properties/lauchSettings.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,以使用 GitHub OAuth 應用程式來驗證用戶端。 驗證之後,API 會將 Cookie 新增至 Web 用戶端回應,再將用戶端重新導向回聊天應用程式。 接著會使用該 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. 儲存您的變更。

更新中樞類別

根據預設,Web 用戶端會使用 Azure SignalR SDK 所產生的存取令牌自動連線到 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. 儲存您的變更。

更新 Web 用戶端程式代碼

  1. 開啟 wwwroot\index.html ,並以程式代碼取代提示使用者名稱的程式代碼,以使用驗證控制器傳回的 Cookie。

    將 index.html式內的getUserName程式代碼更新為下列專案,以使用 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. 叫用中樞方法和 broadcastMessageecho時,更新 onConnected 函式以移除 username 參數:

    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. 執行下列命令,在本機執行 Web 應用程式:

    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 Complete hosted in Azure

    系統會提示您授權聊天應用程式的 GitHub 帳戶存取權。 選取 [授權] 按鈕。

    Authorize OAuth App

    系統會將您重新導向回聊天應用程式,並使用您的 GitHub 帳戶名稱登入。 Web 應用程式會使用您新增的新驗證來驗證您的帳戶名稱。

    Account identified

    透過聊天應用程式現在使用 GitHub 執行驗證,並將驗證資訊儲存為 Cookie,下一個步驟會涉及將它部署至 Azure。 此方法可讓其他使用者使用各自的帳戶進行驗證,並從各種工作站進行通訊。

將應用程式部署至 Azure

備妥環境以使用 Azure CLI:

在本節中,您會使用 Azure CLI 在 Azure App 服務建立新的 Web 應用程式,以在 Azure 中裝載您的 ASP.NET 應用程式。 Web 應用程式已設定為使用本機 Git 部署。 Web 應用程式也會使用您的 SignalR 連接字串、GitHub OAuth 應用程式秘密和部署用戶來設定。

建立下列資源時,請務必使用 SignalR Service 資源所在的相同資源群組。 當您想要移除所有資源時,此方法可讓您稍後更容易清除。 假設您已使用先前 教學課程 SignalRTestResources 中建議的組名範例。

建立 Web 應用程式和方案

複製下列命令的文字,並更新參數。 將更新的腳本貼到 Azure Cloud Shell 中,然後按 Enter 以建立新的 App Service 方案和 Web 應用程式。

#========================================================================
#=== 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
參數 描述
resourceGroupName 在先前的教學課程中建議此資源組名。 最好將所有教學課程資源群組在一起。 使用您在上一個教學課程中使用的相同資源群組。
WebAppPlan 輸入新的唯一 App Service 方案名稱。
WebAppName 此參數是新 Web 應用程式的名稱和 URL 的一部分。 讓它成為唯一的。 例如,signalrtestwebapp22665120。

將應用程式設定新增至 Web 應用程式

在本節中,您會為下列元件新增應用程式設定:

  • SignalR Service 資源 連接字串
  • GitHub OAuth 應用程式用戶端標識碼
  • GitHub OAuth 應用程式客戶端密碼

複製下列命令的文字,並更新參數。 將更新的腳本貼到 Azure Cloud Shell 中,然後按 Enter 以新增應用程式設定:

#========================================================================
#=== 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 為 GitHub OAuth 應用程式指派此變數的密碼。
resourceGroupName 將此變數更新為您在上一節中使用的相同資源組名。
SignalRServiceResource 使用您在快速入門中建立的 SignalR Service 資源名稱來更新此變數。 例如,signalrtestsvc48778624。
WebAppName 使用您在上一節中建立的新 Web 應用程式名稱來更新此變數。

設定本機 Git 部署的 Web 應用程式

在 Azure Cloud Shell 中,貼上下列腳本。 此文稿會使用 Git 將程式代碼部署至 Web 應用程式時,建立您所使用的新部署使用者名稱和密碼。 此腳本也會設定 Web 應用程式以使用本機 Git 存放庫進行部署,並傳回 Git 部署 URL。

#========================================================================
#=== 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
參數 描述
DeploymentUserName 選擇新的部署用戶名稱。
DeploymentUserPassword 選擇新部署用戶的密碼。
resourceGroupName 使用您在上一節中使用的相同資源組名。
WebAppName 此參數是您先前建立的新 Web 應用程式名稱。

記下從此命令傳回的 Git 部署 URL。 您稍後會使用此 URL。

將您的程式代碼部署至 Azure Web 應用程式

若要部署程式代碼,請在 Git 殼層中執行下列命令。

  1. 瀏覽至項目目錄的根目錄。 如果您沒有使用 Git 存放庫初始化專案,請執行下列命令:

    git init
    
  2. 針對您稍早注意到的 Git 部署 URL 新增遠端:

    git remote add Azure <your git deployment url>
    
  3. 暫存初始化存放庫中的所有檔案,並新增認可。

    git add -A
    git commit -m "init commit"
    
  4. 將您的程式代碼部署至 Azure 中的 Web 應用程式。

    git push Azure main
    

    系統會提示您進行驗證,以便將程式代碼部署至 Azure。 輸入您在上面建立之部署使用者的使用者名稱和密碼。

更新 GitHub OAuth 應用程式

最後一件事是更新 GitHub OAuth 應用程式的首頁 URL 和授權回呼 URL,以指向新的託管應用程式。

  1. 在瀏覽器中開啟https://github.com,並流覽至您帳戶的 設定> 開發人員設定>Oauth Apps。

  2. 選取您的驗證應用程式並更新 首頁 URL授權回呼 URL ,如下所示:

    設定 範例
    首頁 URL https://signalrtestwebapp22665120.azurewebsites.net
    授權回呼 URL https://signalrtestwebapp22665120.azurewebsites.net/signin-github
  3. 流覽至您的 Web 應用程式 URL 並測試應用程式。

    OAuth Complete hosted in Azure

清除資源

如果您將繼續進行下一個教學課程,您可以保留在本快速入門中建立的資源,並在下一個教學課程中重複使用它們。

否則,如果您已完成快速入門範例應用程式,您可以刪除本快速入門中建立的 Azure 資源,以避免產生費用。

重要

刪除資源群組是無法復原的,而且資源群組及其中的所有資源都會永久刪除。 請確定您不會不小心刪除錯誤的資源群組或資源。 如果您已建立資源,以將這個範例裝載於包含您想要保留之資源的現有資源群組內,則可以從各自的刀鋒視窗中個別刪除每個資源,而不是刪除資源群組。

登入 Azure 入口網站,然後選取 [資源群組]。

在 [ 依名稱篩選... ] 文本框中,輸入資源群組的名稱。 本文的指示使用了名為 SignalRTestResources 的資源群組。 在結果清單中的資源群組上,按兩下 [...],然後刪除資源群組

Delete

系統會要求您確認刪除資源群組。 輸入要確認的資源群組名稱,然後選取 [ 刪除]。

幾分鐘后,資源群組及其所有自主資源都會被刪除。

下一步

在本教學課程中,您已使用 OAuth 新增驗證,以提供更好的 Azure SignalR 服務驗證方法。 若要深入瞭解如何使用 Azure SignalR Server,請繼續進行 SignalR 服務的 Azure CLI 範例。