分享方式:


Azure SignalR 服務驗證

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

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

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

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

若要深入了解透過 GitHub 所提供的 OAuth 驗證 API,請參閱驗證的基本概念

您可以使用任何程式碼編輯器來完成本快速入門中的步驟。 不過,於 Windows、macOS 和 Linux 平台上所提供的 Visual Studio Code 是項不錯的選擇。

本教學課程的程式碼可於 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 應用程式],然後選取 [OAuth 應用程式] 底下的 [新增 OAuth 應用程式]

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

    設定名稱 建議的值 描述
    應用程式名稱 Azure SignalR Chat GitHub 使用者應該要能夠辨識並信任他們用來進行驗證的應用程式。
    首頁 URL https://localhost:5001
    應用程式說明 搭配使用 Azure SignalR 服務與 GitHub 驗證的聊天室範例 應用程式的實用說明,協助您的應用程式使用者了解所使用驗證的內容。
    授權回呼 URL https://localhost:5001/signin-github 這項設定是 OAuth 應用程式最重要的設定。 GitHub 會在驗證成功後讓使用者返回此回呼 URL。 在本教學課程中,您必須針對 AspNet.Security.OAuth.GitHub 套件 (/signin-github) 使用預設的回呼 URL。
  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 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; }
    }
    

    在程式碼內,AddAuthenticationUseAuthentication 可用來新增 GitHub OAuth 應用程式的驗證支援,而 GetUserCompanyInfoAsync 協助程式方法是範例程式碼,示範如何從 GitHub OAuth 載入公司資訊並儲存至使用者身分識別。 您可能也會注意到,由於 GitHub OAuth 設定了僅傳遞至安全的 https 配置的 secure Cookie,因此使用了 UseHttpsRedirection()。 也別忘了更新本機 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 會在 Web 用戶端回應中新增 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. 儲存您的變更。

更新中樞類別

根據預設,Web 用戶端會使用 Azure SignalR SDK 自動產生的存取權杖連線到 SignalR Service。

在本節中,您會整合實際的驗證工作流程,方法是在中樞類別中新增 Authorize 屬性,並將中樞方法更新為從已驗證使用者的宣告讀取使用者名稱。

  1. 開啟 Hub\ChatSampleHub.cs,並將程式碼更新為下列程式碼片段。 這個程式碼會在 ChatSampleHub 類別中新增 Authorize 屬性,並在中樞方法中使用使用者的已驗證身分識別。 此外,還會新增 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 Service 中建立新的 Web 應用程式,以在 Azure 中裝載 ASP.NET 應用程式。 將 Web 應用程式設定為使用本機 Git 部署。 您也會使用 SignalR 連接字串、GitHub OAuth 應用程式祕密和部署使用者來設定 Web 應用程式。

在建立下列資源時,請務必使用 SignalR 服務資源所在的相同資源群組。 當您之後想要移除所有資源時,這種方法會讓清除作業變得更容易。 所提供的範例假設您使用先前教學課程中所建議的群組名稱 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 服務資源連接字串
  • 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 服務資源名稱來更新此變數。 例如,signalrtestsvc48778624。
WebAppName 使用您在上一節中所建立的新 Web 應用程式名稱來更新此變數。

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

在 Azure Cloud Shell 中貼上下列指令碼。 此指令碼會建立新的部署使用者名稱和密碼,以供您在使用 Git 將程式碼部署至 Web 應用程式時使用。 此指令碼也會使用本機 Git 存放庫來設定部署的 Web 應用程式,並傳回 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應用程式]

  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 伺服器,請繼續進行 SignalR 服務的 Azure CLI 範例。