共用方式為


如何使用 Identity 來保護 SPA 的 Web API 後端

注意

這不是這篇文章的最新版本。 如需目前的版本,請參閱 本文的 .NET 9 版本。

警告

不再支援此版本的 ASP.NET Core。 如需詳細資訊,請參閱 .NET 和 .NET Core 支持原則。 如需目前的版本,請參閱 本文的 .NET 9 版本。

重要

這些發行前產品的相關資訊在產品正式發行前可能會有大幅修改。 Microsoft 對此處提供的資訊,不做任何明確或隱含的瑕疵擔保。

如需目前的版本,請參閱 本文的 .NET 9 版本。

ASP.NET Core Identity 提供可處理驗證、授權和 identity 管理的 API。 API 可讓您使用 cookie 型驗證來保護 Web API 後端的端點。 權杖型選項適用於無法使用 Cookie 的用戶端,但在使用此選項時,您必須負責確保權杖保持安全。 我們建議針對瀏覽器型應用程式使用 Cookie,因為預設情況下,瀏覽器會自動處理它們,而不會將它們公開給 JavaScript。

本文說明如何使用 Identity 來保護 SPA 的 Web API 後端,例如 Angular、React 和 Vue 應用程式。 相同的後端 API 可用來保護 Blazor WebAssembly 應用程式

必要條件

本文所示的步驟會將驗證和授權新增至符合下列情況的 ASP.NET Core Web API 應用程式:

  • 尚未設定驗證。
  • 目標為 net8.0 或更新版本。
  • 可以是最小的 API 或控制器型 API。

本文中的一些測試指示會使用專案範本隨附的 Swagger UI。 不需要 Swagger UI 即可使用 Identity 搭配 Web API 後端。

安裝 NuGet 套件

安裝下列 NuGet 套件:

若要快速開始使用,請使用記憶體內部資料庫。

之後再將資料庫變更為 SQLite 或 SQL Server,以在測試或供生產環境使用時,在工作階段之間儲存使用者資料。 相較於記憶體內部,這引進了一些複雜度,因為它需要透過移轉建立資料庫,如 EF Core 快速入門教學課程所示。

在 Visual Studio 中使用 NuGet 套件管理員dotnet add package CLI 命令來安裝這些套件。

建立 IdentityDbContext

新增名為 ApplicationDbContext 且繼承自 IdentityDbContext<TUser> 的類別:

using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;

public class ApplicationDbContext : IdentityDbContext<IdentityUser>
{
    public ApplicationDbContext(DbContextOptions<ApplicationDbContext> options) :
        base(options)
    { }
}

顯示的程式碼會提供特殊的建構函式,讓您能夠針對不同的環境設定資料庫。

新增這些步驟中顯示的程式碼時,視需要新增一或多個下列 using 指示詞。

using Microsoft.AspNetCore.Identity;
using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using Microsoft.EntityFrameworkCore;

設定 EF Core 內容

如先前所述,開始使用的最簡單方式是使用記憶體內部資料庫。 使用記憶體內部資料庫時,每次執行都會以全新的資料庫開始,且不需要使用移轉。 呼叫 WebApplication.CreateBuilder(args) 之後,新增下列程式碼以將 Identity 設定為使用記憶體內部資料庫:

builder.Services.AddDbContext<ApplicationDbContext>(
    options => options.UseInMemoryDatabase("AppDb"));

若要在測試或供生產環境使用時,在工作階段之間儲存使用者資料,請將資料庫變更為 SQLite 或 SQL Server。

將 Identity 服務新增至容器

呼叫 WebApplication.CreateBuilder(args) 之後,呼叫 AddAuthorization 以將服務新增至相依性插入 (DI) 容器:

builder.Services.AddAuthorization();

啟用 Identity API

呼叫 WebApplication.CreateBuilder(args) 之後,呼叫 AddIdentityApiEndpoints<TUser>(IServiceCollection)AddEntityFrameworkStores<TContext>(IdentityBuilder)

builder.Services.AddIdentityApiEndpoints<IdentityUser>()
    .AddEntityFrameworkStores<ApplicationDbContext>();

預設會同時啟用 Cookie 和專屬權杖。 如果登入端點中 useCookies 查詢字串參數為 true,則會在登入時發出 Cookie 和權杖。

對應 Identity 路由

呼叫 builder.Build() 之後,呼叫 MapIdentityApi<TUser>(IEndpointRouteBuilder) 以對應 Identity 端點:

app.MapIdentityApi<IdentityUser>();

保護選取的端點

若要保護端點,請在定義路由的 Map{Method} 呼叫上使用 RequireAuthorization 擴充方法。 例如:

app.MapGet("/weatherforecast", (HttpContext httpContext) =>
{
    var forecast = Enumerable.Range(1, 5).Select(index =>
        new WeatherForecast
        {
            Date = DateOnly.FromDateTime(DateTime.Now.AddDays(index)),
            TemperatureC = Random.Shared.Next(-20, 55),
            Summary = summaries[Random.Shared.Next(summaries.Length)]
        })
        .ToArray();
    return forecast;
})
.WithName("GetWeatherForecast")
.WithOpenApi()
.RequireAuthorization();

RequireAuthorization 方法也可以用來:

  • 保護 Swagger UI 端點,如下列範例所示:

    app.MapSwagger().RequireAuthorization();
    
  • 使用特定宣告或權限保護,如下列範例所示:

    .RequireAuthorization("Admin");
    

在控制器型 Web API 專案中,將 [Authorize] 屬性套用至控制器或動作,以保護端點。

測試 API

測試驗證的快速方式是使用專案範本隨附的記憶體內部資料庫和 Swagger UI。 下列步驟示範如何使用 Swagger UI 測試 API。 請確定 Swagger UI 端點未受到保護

嘗試存取受保護的端點

  • 執行應用程式並瀏覽至 Swagger UI。
  • 展開受保護的端點,例如透過 Web API 範本所建立專案中的 /weatherforecast
  • 選取 [試試看]。
  • 選取 [執行]。 回應為 401 - not authorized

測試註冊

  • 展開 /register 並選取 [試用]

  • 在 UI 的 [參數] 區段中,會顯示範例要求本文:

    {
      "email": "string",
      "password": "string"
    }
    
  • 以有效的電子郵件地址和密碼取代 "string",然後選取 [執行]

    若要符合預設的密碼驗證規則,密碼長度必須至少為六個字元,且至少包含下列每一個字元之一:

    • 大寫字母
    • 小寫字母
    • 數字
    • 非英數字元

    如果您輸入無效的電子郵件地址或錯誤的密碼,結果會包含驗證錯誤。 以下是回應本文的範例,其中包含驗證錯誤:

    {
      "type": "https://tools.ietf.org/html/rfc9110#section-15.5.1",
      "title": "One or more validation errors occurred.",
      "status": 400,
      "errors": {
        "PasswordTooShort": [
          "Passwords must be at least 6 characters."
        ],
        "PasswordRequiresNonAlphanumeric": [
          "Passwords must have at least one non alphanumeric character."
        ],
        "PasswordRequiresDigit": [
          "Passwords must have at least one digit ('0'-'9')."
        ],
        "PasswordRequiresLower": [
          "Passwords must have at least one lowercase ('a'-'z')."
        ]
      }
    }
    

    錯誤會以 ProblemDetails 格式傳回,因此用戶端可以剖析錯誤,並視需要顯示驗證錯誤。

    成功的註冊會導致 200 - OK 回應。

測試登入

  • 展開 /login 並選取 [試用]。範例要求本文會顯示兩個額外的參數:

    {
      "email": "string",
      "password": "string",
      "twoFactorCode": "string",
      "twoFactorRecoveryCode": "string"
    }
    

    此範例不需要額外的 JSON 屬性,因此可以刪除。 將 useCookies 設定為 true

  • 將 "string" 取代為您用來註冊的電子郵件地址和密碼,然後選取 [執行]

    成功的登入會導致回應標頭的 200 - OK 回應具有 cookie。

重新測試受保護的端點

成功登入之後,請重新執行受保護的端點。 驗證 cookie 會自動隨著要求傳送,而且端點已獲得授權。 Cookie 型驗證會安全地內建至瀏覽器並「正常運作」。

使用非瀏覽器用戶端測試

某些 Web 用戶端預設可能不會在標頭中包含 Cookie:

  • 如果您使用工具來測試 API,您可能需要在設定中啟用 Cookie。

  • JavaScript fetch API 預設不會包含 Cookie。 藉由在選項中將 credentials 設定為值 include 來啟用它們。

  • 在 Blazor WebAssembly 應用程式中執行的 HttpClient 需要 HttpRequestMessage 以包含認證,如下列範例所示:

    request.SetBrowserRequestCredential(BrowserRequestCredentials.Include);
    

使用權杖型驗證

我們建議在瀏覽器型應用程式中使用 Cookie,因為預設情況下,瀏覽器會自動處理它們,而不會將它們公開給 JavaScript。

系統會發出可用來驗證後續要求的自訂權杖 (ASP.NET Core identity 平台專屬的權杖)。 權杖會以持有人權杖的形式傳入 Authorization 標頭。 也會提供重新整理權杖。 此權杖可讓應用程式在舊權杖到期時要求新的權杖,而不需要強制使用者重新登入。

權杖不是標準的 JSON Web 權杖 (JWT)。 使用自訂權杖是刻意的,因為內建的 Identity API 主要用於簡單案例。 權杖選項不是用來作為功能完整的 identity 服務提供者或權杖伺服器,而是作為無法使用 Cookie 用戶端的 cookie 選項的替代方案。

若要使用權杖型驗證,請在呼叫 /login 端點時,將 useCookies 查詢字串參數設定為 false。 權杖會使用持有人驗證配置。 使用從呼叫 /login 傳回的權杖,對受保護端點的後續呼叫應該新增標頭 Authorization: Bearer <token>,其中的 <token> 是存取權杖。 如需詳細資訊,請參閱本文稍後的使用 POST /login 端點

登出

若要提供讓使用者登出的方式,請定義 /logout 端點,如下列範例所示:

app.MapPost("/logout", async (SignInManager<IdentityUser> signInManager,
    [FromBody] object empty) =>
{
    if (empty != null)
    {
        await signInManager.SignOutAsync();
        return Results.Ok();
    }
    return Results.Unauthorized();
})
.WithOpenApi()
.RequireAuthorization();

呼叫此端點時,在要求本文中提供空的 JSON 物件 ({})。 下列程式碼是對登出端點的呼叫範例:

public signOut() {
  return this.http.post('/logout', {}, {
    withCredentials: true,
    observe: 'response',
    responseType: 'text'

MapIdentityApi<TUser> 端點

MapIdentityApi<TUser> 的呼叫會將下列端點新增至應用程式:

使用 POST /register 端點

要求本文必須具有 EmailPassword 屬性:

{
  "email": "string",
  "password": "string",
}

如需詳細資訊,請參閱

使用 POST /login 端點

在要求本文中,EmailPassword 是必要的。 如果已啟用雙重要素驗證 (2FA),則需要 TwoFactorCodeTwoFactorRecoveryCode。 如果未啟用 2FA,則省略 twoFactorCodetwoFactorRecoveryCode。 如需詳細資訊,請參閱本文稍後的使用 POST /manage/2fa 端點

以下是未啟用 2FA 的要求本文範例:

{
  "email": "string",
  "password": "string"
}

以下是已啟用 2FA 的要求本文範例:

  • {
      "email": "string",
      "password": "string",
      "twoFactorCode": "string",
    }
    
  • {
      "email": "string",
      "password": "string",
      "twoFactorRecoveryCode": "string"
    }
    

端點需要查詢字串參數:

  • useCookies - 設定為 true 以進行 cookie 型驗證。 設定為 false 或省略以進行權杖型驗證。

如需 cookie 型驗證的詳細資訊,請參閱本文稍早的測試登入

權杖型驗證

如果 useCookiesfalse 或省略,則會啟用權杖型驗證。 回應本文包含下列屬性:

{
  "tokenType": "string",
  "accessToken": "string",
  "expiresIn": 0,
  "refreshToken": "string"
}

如需這些內容的相關資訊,請參閱 AccessTokenResponse

將存取權杖放在標頭中以提出已驗證的要求,如下列範例所示

Authorization: Bearer {access token}

當存取權杖即將到期時,呼叫 /refresh 端點。

使用 POST /refresh 端點

僅適用權杖型驗證。 取得新的存取權杖,而不強制使用者重新登入。 當存取權杖即將到期時,呼叫此端點。

要求本文只包含 RefreshToken。 以下是要求本文範例:

{
  "refreshToken": "string"
}

如果呼叫成功,回應主體為新的 AccessTokenResponse,如下列範例所示:

{
  "tokenType": "string",
  "accessToken": "string",
  "expiresIn": 0,
  "refreshToken": "string"
}

使用 GET /confirmEmail 端點

如果已設定 Identity 進行電子郵件確認,則對 /register 端點的成功呼叫會傳送包含 /confirmEmail 端點連結的電子郵件。 連結包含下列查詢字串參數:

  • userId
  • code
  • changedEmail - 只有在使用者於註冊期間變更電子郵件地址時才包含。

Identity 會提供確認電子郵件的預設文字。 根據預設,電子郵件主旨為「確認您的電子郵件」,而電子郵件本文看起來像下列範例:

 Please confirm your account by <a href='https://contoso.com/confirmEmail?userId={user ID}&code={generated code}&changedEmail={new email address}'>clicking here</a>.

如果 RequireConfirmedEmail 屬性設定為 true,使用者必須在按一下電子郵件中的連結來確認電子郵件地址之後才能登入。 /confirmEmail 端點:

  • 確認電子郵件地址,並讓使用者登入。
  • 在回應本文中傳回文字「感謝您確認您的電子郵件」。

若要設定 Identity 以進行電子郵件確認,請在 Program.cs 中新增程式碼,以將 RequireConfirmedEmail 設定為 true,並將實作 IEmailSender 的類別新增至 DI 容器。 例如:

builder.Services.Configure<IdentityOptions>(options =>
{
    options.SignIn.RequireConfirmedEmail = true;
});

builder.Services.AddTransient<IEmailSender, EmailSender>();

如需詳細資訊,請參閱 ASP.NET Core 中的帳戶確認和密碼復原

Identity 也會為需要傳送的其他電子郵件提供預設文字,例如用於 2FA 和密碼重設。 若要自訂這些電子郵件,請提供 IEmailSender 介面的自訂實作。 在上述範例中,EmailSender 是實作 IEmailSender 的類別。 如需詳細資訊,包括實作 IEmailSender 的類別範例,請參閱 ASP.NET Core 中的帳戶確認和密碼復原

使用 POST /resendConfirmationEmail 端點

只有當位址對已註冊的使用者有效時,才傳送電子郵件。

要求本文只包含 Email。 以下是要求本文範例:

{
  "email": "string"
}

如需詳細資訊,請參閱本文稍早使用 GET /confirmEmail 端點

使用 POST /forgotPassword 端點

產生包含密碼重設代碼的電子郵件。 使用新密碼將該代碼傳送到 /resetPassword

要求本文只包含 Email。 以下是範例:

{
  "email": "string"
}

如需如何啟用 Identity 以傳送電子郵件的相關資訊,請參閱使用 GET /confirmEmail 端點

使用 POST /resetPassword 端點

藉由呼叫 /forgotPassword 端點取得重設代碼之後,呼叫此端點。

要求本文需要 EmailResetCodeNewPassword。 以下是範例:

{
  "email": "string",
  "resetCode": "string",
  "newPassword": "string"
}

使用 POST /manage/2fa 端點

為使用者設定雙重要素驗證 (2FA)。 啟用 2FA 時,除了電子郵件地址和密碼之外,成功登入還需要驗證器應用程式所產生的代碼。

啟用 2FA

若要為目前驗證的使用者啟用 2FA:

  • 呼叫 /manage/2fa 端點,在要求本文中傳送空的 JSON 物件 ({})。

  • 回應本文會提供 SharedKey,以及目前不需要的一些其他屬性。 共用金鑰是用來設定驗證器應用程式。 回應本文範例:

    {
      "sharedKey": "string",
      "recoveryCodesLeft": 0,
      "recoveryCodes": null,
      "isTwoFactorEnabled": false,
      "isMachineRemembered": false
    }
    
  • 使用共用金鑰來取得以時間為基礎的一次性密碼 (TOTP)。 如需詳細資訊,請參閱為在 ASP.NET Core 中為 TOTP 驗證器應用程式啟用產生 QR 代碼

  • 呼叫 /manage/2fa 端點,在要求本文中傳送 TOTP 和 "enable": true。 例如:

    {
      "enable": true,
      "twoFactorCode": "string"
    }
    
  • 回應本文會確認 IsTwoFactorEnabled 為 true,並提供 RecoveryCodes。 當驗證器應用程式無法使用時,會使用復原碼來登入。 成功啟用 2FA 之後的回應本文範例:

    {
      "sharedKey": "string",
      "recoveryCodesLeft": 10,
      "recoveryCodes": [
        "string",
        "string",
        "string",
        "string",
        "string",
        "string",
        "string",
        "string",
        "string",
        "string"
      ],
      "isTwoFactorEnabled": true,
      "isMachineRemembered": false
    }
    

使用 2FA 登入

呼叫 /login 端點,並在要求本文中傳送電子郵件地址、密碼和 TOTP。 例如:

{
  "email": "string",
  "password": "string",
  "twoFactorCode": "string"
}

如果使用者無法存取驗證器應用程式,請使用啟用 2FA 時提供的其中一個復原碼呼叫 /login 端點來登入。 要求本文看起來像下列範例:

{
  "email": "string",
  "password": "string",
  "twoFactorRecoveryCode": "string"
}

重設復原碼

若要取得新的復原碼集合,請呼叫此端點,並將 ResetRecoveryCodes 設定為 true。 以下是要求本文範例:

{
  "resetRecoveryCodes": true
}

重設共用金鑰

若要取得新的隨機共用金鑰,請呼叫此端點,並將 ResetSharedKey 設定為 true。 以下是要求本文範例:

{
  "resetSharedKey": true
}

重設金鑰會自動停用已驗證使用者的雙重要素登入需求,直到稍後要求重新啟用為止。

忘記電腦

若要清除出現的 cookie「記住我旗標」,請呼叫此端點,並將 ForgetMachine 設定為 true。 以下是要求本文範例:

{
  "forgetMachine": true
}

此端點不會影響權杖型驗證。

使用 GET /manage/info 端點

取得已登入使用者的電子郵件地址和電子郵件確認狀態。 基於安全性考量,已從此端點省略宣告。 如果需要宣告,請使用伺服器端 API 來設定宣告的端點。 或者,不要共用所有使用者的宣告,而是提供可接受宣告並回應使用者是否有宣告的驗證端點。

要求不需要任何參數。 回應本文包含 EmailIsEmailConfirmed 屬性,如下列範例所示:

{
  "email": "string",
  "isEmailConfirmed": true
}

使用 POST /manage/info 端點

更新登入使用者的電子郵件地址和密碼。 在要求本文中傳送 NewEmailNewPasswordOldPassword,如下列範例所示:

{
  "newEmail": "string",
  "newPassword": "string",
  "oldPassword": "string"
}

以下是回應本文的範例:

{
  "email": "string",
  "isEmailConfirmed": false
}

另請參閱

如需詳細資訊,請參閱以下資源:

ASP.NET 核心範本會使用 API 授權的支援,在單頁應用程式 (SPA) 中提供驗證。 用於驗證和儲存使用者的 ASP.NET Core Identity 與用於實作 OpenID Connect 的 Duende Identity Server 相結合。

重要

Duende Software 可能會要求您支付授權費用才能在生產環境中使用 Duende Identity 伺服器。 如需詳細資訊,請參閱從 ASP.NET Core 5.0 移轉至 6.0

驗證參數已新增至 AngularReact 專案範本,與 Web 應用程式 (Model-View-Controller) (MVC) 和 Web 應用程式 (Razor Pages) 專案範本中的驗證參數類似。 允許的參數值為 NoneIndividualReact.js 和 Redux 專案範本目前不支援驗證參數。

建立具有 API 授權支援的應用程式

使用者驗證和授權可以搭配 Angular 和 React SPA 使用。 開啟命令殼層,並執行下列命令:

Angular

dotnet new angular -au Individual

React

dotnet new react -au Individual

上述命令會使用包含 SPA 的 ClientApp 目錄,建立 ASP.NET Core 應用程式。

應用程式的 ASP.NET Core 元件的一般描述

下列各節說明在包含驗證支援時新增至專案:

Program.cs

下列程式碼範例依賴 Microsoft.AspNetCore.ApiAuthorization.IdentityServer NuGet 套件。 這些範例會使用 AddApiAuthorizationAddIdentityServerJwt 擴充方法來設定 API 驗證和授權。 使用 React 或 Angular SPA 專案範本進行驗證的專案包含此套件的參考。

dotnet new angular -au Individual 會產生下列 Program.cs 檔案:

using Microsoft.AspNetCore.Authentication;
using Microsoft.EntityFrameworkCore;
using output_directory_name.Data;
using output_directory_name.Models;

var builder = WebApplication.CreateBuilder(args);

var connectionString = builder.Configuration.GetConnectionString("DefaultConnection") ?? throw new InvalidOperationException("Connection string 'DefaultConnection' not found.");
builder.Services.AddDbContext<ApplicationDbContext>(options =>
    options.UseSqlite(connectionString));
builder.Services.AddDatabaseDeveloperPageExceptionFilter();

builder.Services.AddDefaultIdentity<ApplicationUser>(options => options.SignIn.RequireConfirmedAccount = true)
    .AddEntityFrameworkStores<ApplicationDbContext>();

builder.Services.AddIdentityServer()
    .AddApiAuthorization<ApplicationUser, ApplicationDbContext>();

builder.Services.AddAuthentication()
    .AddIdentityServerJwt();

builder.Services.AddControllersWithViews();
builder.Services.AddRazorPages();

var app = builder.Build();

if (app.Environment.IsDevelopment())
{
    app.UseMigrationsEndPoint();
}
else
{
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();

app.UseAuthentication();
app.UseIdentityServer();
app.UseAuthorization();

app.MapControllerRoute(
    name: "default",
    pattern: "{controller}/{action=Index}/{id?}");
app.MapRazorPages();

app.MapFallbackToFile("index.html");

app.Run();

上述程式碼會設定:

  • Identity 使用預設 UI:

    builder.Services.AddDbContext<ApplicationDbContext>(options =>
        options.UseSqlite(connectionString));
    builder.Services.AddDatabaseDeveloperPageExceptionFilter();
    
    builder.Services.AddDefaultIdentity<ApplicationUser>(options => options.SignIn.RequireConfirmedAccount = true)
        .AddEntityFrameworkStores<ApplicationDbContext>();
    
  • 搭配附加的 AddApiAuthorization 協助程式方法 (它在 IdentityServer 之上設定一些預設的 ASP.NET Core 慣例) 的 IdentityServer:

    builder.Services.AddIdentityServer()
        .AddApiAuthorization<ApplicationUser, ApplicationDbContext>();
    
  • 搭配附加的 AddIdentityServerJwt 協助程式方法 (它會設定應用程式以驗證 IdentityServer 所產生的 JWT 權杖) 的驗證:

    builder.Services.AddAuthentication()
    .AddIdentityServerJwt();
    
  • 驗證中介軟體負責驗證要求認證,並在要求內容上設定使用者:

    app.UseAuthentication();
    
  • 公開 OpenID Connect 端點的 IdentityServer 中介軟體:

    app.UseIdentityServer();
    

警告

本文說明如何使用 連接字串。 使用本機資料庫時,使用者不需要經過驗證,但在生產環境中,連接字串 有時會包含要驗證的密碼。 資源擁有者密碼認證 (ROPC) 是生產資料庫中應避免的安全性風險。 實際執行應用程式應該使用可用的最安全驗證流程。 如需部署至測試或生產環境之應用程式驗證的詳細資訊,請參閱 保護驗證流程

Linux 上的 Azure App Service

針對 Linux 上的 Azure App Service 部署,請明確指定簽發者:

builder.Services.Configure<JwtBearerOptions>(
    IdentityServerJwtConstants.IdentityServerJwtBearerScheme, 
    options =>
    {
        options.Authority = "{AUTHORITY}";
    });

在上述程式碼中,{AUTHORITY} 預留位置是進行 OpenID Connect 呼叫時要使用的 Authority

範例:

options.Authority = "https://contoso-service.azurewebsites.net";

AddApiAuthorization

此協助程式方法會將 IdentityServer 設定為使用我們支援的設定。 IdentityServer 是一個強大且可擴充的架構,用於處理應用程式的安全性問題。 同時,針對最常見的案例,公開不必要的複雜性。 因此,系統會將一組慣例和組態選項提供給您,這些選項會被視為良好的起點。 驗證需求變更後,仍可使用 IdentityServer 的完整功能來自訂驗證,以符合您的需求。

AddIdentityServerJwt

這個協助程式方法會將應用程式的原則配置設定為預設的驗證處理常式。 原則已設定為讓 Identity 處理路由至 Identity URL 空間 "/Identity" 中任何子路徑的所有要求。 JwtBearerHandler 會處理所有其他要求。 此外,此方法會向預設範圍為 <<ApplicationName>>API 的 IdentityServer 註冊 <<ApplicationName>>API API 資源,並設定 JWT 持有人權杖中介軟體來驗證應用程式 IdentityServer 所簽發的權杖。

WeatherForecastController

在檔案中,請注意套用至類別的 [Authorize] 屬性,指出使用者必須根據預設原則來存取資源。 預設授權原則會設定為使用預設驗證配置,此配置是由上述原則配置 AddIdentityServerJwt 所設定,使得這類協助程式方法所設定 JwtBearerHandler 應用程式要求的預設處理常式。

ApplicationDbContext

在檔案中,請注意 Identity 使用相同的 DbContext,但例外狀況是它會擴充 ApiAuthorizationDbContext (IdentityDbContext 的衍生類別),以包含 IdentityServer 的結構描述。

若要取得資料庫結構描述的完全控制權,請從其中一個可用的 IdentityDbContext 繼承,並透過在 OnModelCreating 方法上呼叫 builder.ConfigurePersistedGrantContext(_operationalStoreOptions.Value) 來將內容設定為包含 Identity 結構描述。

OidcConfigurationController

在檔案中,請注意佈建的端點,以提供用戶端需要使用的 OIDC 參數。

appsettings.json

在專案根目錄的 appsettings.json 檔案中,有一個新的 IdentityServer 區段描述已設定的用戶端清單。 在下列的範例中,有一個單一的用戶端。 用戶端名稱會對應至應用程式名稱,並依照慣例對應至 OAuth ClientId 參數。 設定檔指出正在設定的應用程式類型。 它會在內部用來驅動慣例,以簡化伺服器的設定處理過程。 有數個設定檔可供使用,如應用程式設定檔一節所述。

"IdentityServer": {
  "Clients": {
    "angularindividualpreview3final": {
      "Profile": "IdentityServerSPA"
    }
  }
}

appsettings.Development.json

在專案根目錄的 appsettings.Development.json 檔案中,有一個 IdentityServer 區段描述用來簽署權杖的金鑰。 部署至生產環境時,必須與應用程式一起布建和部署金鑰,如部署至生產一節所述。

"IdentityServer": {
  "Key": {
    "Type": "Development"
  }
}

Angular 應用程式的一般描述

Angular 範本中的驗證和 API 授權支援位於 ClientApp/src/API-authorization 目錄中自己的 Angular 模組中。 模組是由下列元素所組成:

  • 3 個元件:
    • login.component.ts:處理應用程式的登入流程。
    • logout.component.ts:處理應用程式的登出流程。
    • login-menu.component.ts:顯示下列其中一組連結的 Widget:
      • 使用者驗證時,使用者設定檔管理和登出連結。
      • 使用者未通過驗證時註冊和登入連結。
  • 路由保護 AuthorizeGuard 可以新增至路由,並要求使用者在瀏覽路由之前先進行驗證。
  • HTTP 攔截器 AuthorizeInterceptor,會在使用者通過驗證時,將存取權杖附加至以 API 為目標的傳出 HTTP 要求。
  • 服務 AuthorizeService 處理驗證過程的較低層級詳細資訊,並將有關經過驗證的用戶的資訊公開給應用程式的 rest 以供取用。
  • Angular 模組,定義與應用程式驗證部分相關聯的路由。 它會公開登入功能表元件、攔截器、保護和服務,以便從應用程式的 rest 取用。

React 應用程式的一般描述

React 範本中的驗證和 API 授權支援位於 ClientApp/src/components/api-authorization 目錄中。 它是由下列元素所組成:

  • 4 個元件:
    • Login.js:處理應用程式的登入流程。
    • Logout.js:處理應用程式的登出流程。
    • LoginMenu.js:顯示下列其中一組連結的 Widget:
      • 使用者驗證時,使用者設定檔管理和登出連結。
      • 使用者未通過驗證時註冊和登入連結。
    • AuthorizeRoute.js:在轉譯 Component 參數中所指示的元件之前,必須先驗證使用者的路由元件。
  • 類別 AuthorizeService 的匯出 authService 執行個體,用於處理驗證過程的較低層級詳細資訊,並將有關經過驗證的使用者的資訊公開給應用程式的 rest 以供取用。

既然您已了解解決方案的主要元件,您可以更深入地查看應用程式的個別情節。

需要新 API 的授權

根據預設,系統會設定為輕鬆要求新 API 的授權。 若要這樣做,請建立新的控制器,並將 [Authorize] 屬性新增至控制器類別或控制器內的任何動作。

自訂 API 驗證處理常式

若要自訂 API JWT 處理常式的組態,請設定其 JwtBearerOptions 執行個體:

builder.Services.AddAuthentication()
    .AddIdentityServerJwt();

builder.Services.Configure<JwtBearerOptions>(
    IdentityServerJwtConstants.IdentityServerJwtBearerScheme,
    options =>
    {
        ...
    });

API 的 JWT 處理常式會引發事件,以使用 JwtBearerEvents 啟用驗證程式的控制權。 若要提供 API 授權的支援,AddIdentityServerJwt 註冊自己的事件處理常式。

若要自訂事件的處理,請視需要以其他邏輯包裝現有的事件處理常式。 例如:

builder.Services.Configure<JwtBearerOptions>(
    IdentityServerJwtConstants.IdentityServerJwtBearerScheme,
    options =>
    {
        var onTokenValidated = options.Events.OnTokenValidated;       

        options.Events.OnTokenValidated = async context =>
        {
            await onTokenValidated(context);
            ...
        }
    });

在上述的程式碼中,OnTokenValidated 事件處理常式被自訂實作所取代。 此實作:

  1. 呼叫 API 授權支援所提供的原始實作。
  2. 執行自己的自訂邏輯。

保護用戶端路由 (Angular)

若要保護用戶端路由,請在設定路由時,將授權保護新增至要執行的保護清單來完成。 例如,您可以看到主要應用程式 Angular 模組內如何設定 fetch-data 路由:

RouterModule.forRoot([
  // ...
  { path: 'fetch-data', component: FetchDataComponent, canActivate: [AuthorizeGuard] },
])

請務必提及保護路由不會保護實際端點 (這仍然需要套用 [Authorize] 屬性),但只會防止使用者在未通過驗證時瀏覽至指定的用戶端路由。

驗證 API 要求 (Angular)

透過使用應用程式所定義的 HTTP 用戶端攔截器,自動驗證與應用程式一起裝載之 API 的要求。

保護用戶端路由 (React)

使用 AuthorizeRoute 元件而非純 Route 元件來保護用戶端路由。 例如,請注意如何在 App 元件內設定 fetch-data 路由:

<AuthorizeRoute path='/fetch-data' component={FetchData} />

保護路由:

  • 不會保護實際端點 (這仍然需要套用 [Authorize] 屬性)。
  • 只有在未通過驗證時,使用者才能瀏覽至指定的用戶端路由。

驗證 API 要求 (React)

使用 React 驗證要求是先從 AuthorizeService 匯入 authService 執行個體來完成。 存取權杖是從 authService 擷取,並附加至要求,如下所示。 在 React 元件中,這項工作通常是在 componentDidMount 生命週期方法中完成,或因為某些使用者互動而產生。

authService 匯入元件

import authService from './api-authorization/AuthorizeService'

擷取並附加存取權杖至回應

async populateWeatherData() {
  const token = await authService.getAccessToken();
  const response = await fetch('api/SampleData/WeatherForecasts', {
    headers: !token ? {} : { 'Authorization': `Bearer ${token}` }
  });
  const data = await response.json();
  this.setState({ forecasts: data, loading: false });
}

部署至生產位置

若要將應用程式部署至生產環境,必須佈建下列資源:

  • 用來儲存 Identity 使用者帳戶和 IdentityServer 授與的資料庫。
  • 用於簽署權杖的生產憑證。
    • 此憑證沒有特定需求;它可以是自我簽署憑證或透過 CA 授權單位佈建的憑證。
    • 它可透過 PowerShell 或 OpenSSL 等標準工具產生。
    • 它可以安裝在目的電腦上的憑證存放區中,或部署為具有強式密碼的 .pfx 檔案。

範例:部署至非 Azure Web 裝載提供者

在您的 Web 主控面板中,建立或載入您的憑證。 然後在應用程式的 appsettings.json 檔案中,修改 IdentityServer 區段以包含金鑰詳細資料。 例如:

"IdentityServer": {
  "Key": {
    "Type": "Store",
    "StoreName": "WebHosting",
    "StoreLocation": "CurrentUser",
    "Name": "CN=MyApplication"
  }
}

在前述範例中:

  • StoreName 代表儲存憑證的憑證存放區名稱。 在此情況下,它會指向 Web 裝載存放區。
  • StoreLocation 代表從何處載入憑證 (在此案例中為 CurrentUser)。
  • Name 對應至憑證的辨別主體。

範例:部署至 Azure App Service

本節說明如何使用儲存在憑證存放區中的憑證,將應用程式部署至 Azure App Service。 若要修改應用程式以從憑證存放區載入憑證,當您在稍後的步驟中設定 Azure 入口網站應用程式時,需要標準層服務方案或更好的方案。

在應用程式的 appsettings.json 檔案中,修改 IdentityServer 區段以包含金鑰詳細資料:

"IdentityServer": {
  "Key": {
    "Type": "Store",
    "StoreName": "My",
    "StoreLocation": "CurrentUser",
    "Name": "CN=MyApplication"
  }
}
  • 存放區名稱代表儲存憑證的憑證存放區名稱。 在此情況下,它會指向個人使用者存放區。
  • 存放區位置代表從 (CurrentUserLocalMachine) 載入憑證的位置。
  • 憑證上的 name 屬性會對應至憑證的辨別主體。

若要部署至 Azure App Service,請遵循將應用程式部署至 Azure 中的步驟,其中說明如何建立必要的 Azure 資源,並將應用程式部署至生產環境。

遵循上述指示之後,應用程式會部署至 Azure,但尚無法運作。 應用程式所使用的憑證必須在 Azure 入口網站中設定。 找出憑證的指紋,並遵循載入憑證中所述的步驟。

雖然這些步驟提到 SSL,但 Azure 入口網站中有私人憑證區段,您可以在其中上傳佈建的憑證以搭配應用程式使用。

在 Azure 入口網站中設定應用程式和應用程式的設定之後,請在入口網站中重新啟動應用程式。

其他組態選項

API 授權的支援建置在 IdentityServer 之上,其中包含一組慣例、預設值和增強功能,以簡化 SPA 的體驗。 不用說,如果 ASP.NET Core 整合未涵蓋您的案例,IdentityServer 的完整功能就會在幕後提供。 ASP.NET 核心支援著重於「第一方」應用程式,其中所有應用程式都是由我們的組織建立和部署。 因此,不支援同意或同盟等專案。 在這些案例中,請使用 IdentityServer 並遵循其文件。

應用程式設定檔

應用程式設定檔是進一步定義其參數之應用程式的預先定義組態。 目前支援下列設定檔:

  • IdentityServerSPA:代表託管於 IdentityServer 作為單一單位的 SPA。
    • redirect_uri 預設為 /authentication/login-callback
    • post_logout_redirect_uri 預設為 /authentication/logout-callback
    • 一組範圍包含 openidprofile 和針對應用程式中 API 所定義的每個範圍。
    • 允許的 OIDC 回應類型集是 id_token token 或每個單獨的回應類型 (id_token, token)。
    • 允許的回應模式為 fragment
  • SPA:代表未託管於 IdentityServe 的 SPA。
    • 一組範圍包含 openidprofile 和針對應用程式中 API 所定義的每個範圍。
    • 允許的 OIDC 回應類型集是 id_token token 或每個單獨的回應類型 (id_token, token)。
    • 允許的回應模式為 fragment
  • IdentityServerJwt:代表與 IdentityServe 一起託管的 API。
    • 應用程式設定為具有預設為應用程式名稱的單一範圍。
  • API:代表未託管於 IdentityServer 的 API。
    • 應用程式設定為具有預設為應用程式名稱的單一範圍。

透過 AppSettings 設定

透過組態系統設定應用程式,方法是將它們新增至 ClientsResources 清單。

設定每個用戶端的 redirect_uripost_logout_redirect_uri 屬性,如下列範例所示:

"IdentityServer": {
  "Clients": {
    "MySPA": {
      "Profile": "SPA",
      "RedirectUri": "https://www.example.com/authentication/login-callback",
      "LogoutUri": "https://www.example.com/authentication/logout-callback"
    }
  }
}

設定資源時,您可以設定資源的範圍,如下所示:

"IdentityServer": {
  "Resources": {
    "MyExternalApi": {
      "Profile": "API",
      "Scopes": "a b c"
    }
  }
}

透過程式碼設定

您也可以透過使用多載 AddApiAuthorization 的程式碼來設定用戶端和資源,以採取動作來設定選項。

AddApiAuthorization<ApplicationUser, ApplicationDbContext>(options =>
{
    options.Clients.AddSPA(
        "My SPA", spa =>
        spa.WithRedirectUri("http://www.example.com/authentication/login-callback")
           .WithLogoutRedirectUri(
               "http://www.example.com/authentication/logout-callback"));

    options.ApiResources.AddApiResource("MyExternalApi", resource =>
        resource.WithScopes("a", "b", "c"));
});

其他資源

ASP.NET Core 3.1 和更新版本的範本會使用 API 授權的支援,在單頁應用程式 (SPA) 中提供驗證。 用於驗證和儲存使用者的 ASP.NET Core Identity 與用於實作 OpenID Connect 的 IdentityServer 相結合。

驗證參數已新增至 AngularReact 專案範本,與 Web 應用程式 (Model-View-Controller) (MVC) 和 Web 應用程式 (Razor Pages) 專案範本中的驗證參數類似。 允許的參數值為 NoneIndividualReact.js 和 Redux 專案範本目前不支援驗證參數。

建立具有 API 授權支援的應用程式

使用者驗證和授權可以搭配 Angular 和 React SPA 使用。 開啟命令殼層,並執行下列命令:

Angular

dotnet new angular -o <output_directory_name> 

React

dotnet new react -o <output_directory_name> -au Individual

上述命令會使用包含 SPA 的 ClientApp 目錄,建立 ASP.NET Core 應用程式。

應用程式的 ASP.NET Core 元件的一般描述

下列各節說明在包含驗證支援時新增至專案:

Startup 類別

下列程式碼範例依賴 Microsoft.AspNetCore.ApiAuthorization.IdentityServer NuGet 套件。 這些範例會使用 AddApiAuthorizationAddIdentityServerJwt 擴充方法來設定 API 驗證和授權。 使用 React 或 Angular SPA 專案範本進行驗證的專案包含此套件的參考。

Startup 類別有下列新增項目:

  • Startup.ConfigureServices 方法內:

    • Identity 使用預設 UI:

      services.AddDbContext<ApplicationDbContext>(options =>
          options.UseSqlite(Configuration.GetConnectionString("DefaultConnection")));
      
      services.AddDefaultIdentity<ApplicationUser>()
          .AddEntityFrameworkStores<ApplicationDbContext>();
      
    • 搭配附加的 AddApiAuthorization 協助程式方法 (它在 IdentityServer 之上設定一些預設的 ASP.NET Core 慣例) 的 IdentityServer:

      services.AddIdentityServer()
          .AddApiAuthorization<ApplicationUser, ApplicationDbContext>();
      
    • 搭配附加的 AddIdentityServerJwt 協助程式方法 (它會設定應用程式以驗證 IdentityServer 所產生的 JWT 權杖) 的驗證:

      services.AddAuthentication()
          .AddIdentityServerJwt();
      
  • Startup.Configure 方法內:

    • 驗證中介軟體負責驗證要求認證,並在要求內容上設定使用者:

      app.UseAuthentication();
      
    • 公開 OpenID Connect 端點的 IdentityServer 中介軟體:

      app.UseIdentityServer();
      

警告

本文說明如何使用 連接字串。 使用本機資料庫時,使用者不需要經過驗證,但在生產環境中,連接字串 有時會包含要驗證的密碼。 資源擁有者密碼認證 (ROPC) 是生產資料庫中應避免的安全性風險。 實際執行應用程式應該使用可用的最安全驗證流程。 如需部署至測試或生產環境之應用程式驗證的詳細資訊,請參閱 保護驗證流程

Linux 上的 Azure App Service

針對 Linux 上的 Azure App Service 部署,請在 Startup.ConfigureServices 中明確指定簽發者:

services.Configure<JwtBearerOptions>(
    IdentityServerJwtConstants.IdentityServerJwtBearerScheme, 
    options =>
    {
        options.Authority = "{AUTHORITY}";
    });

在上述程式碼中,{AUTHORITY} 預留位置是進行 OpenID Connect 呼叫時要使用的 Authority

範例:

options.Authority = "https://contoso-service.azurewebsites.net";

AddApiAuthorization

此協助程式方法會將 IdentityServer 設定為使用我們支援的設定。 IdentityServer 是一個強大且可擴充的架構,用於處理應用程式的安全性問題。 同時,針對最常見的案例,公開不必要的複雜性。 因此,系統會將一組慣例和組態選項提供給您,這些選項會被視為良好的起點。 驗證需求變更後,仍可使用 IdentityServer 的完整功能來自訂驗證,以符合您的需求。

AddIdentityServerJwt

這個協助程式方法會將應用程式的原則配置設定為預設的驗證處理常式。 原則已設定為讓 Identity 處理路由至 Identity URL 空間 "/Identity" 中任何子路徑的所有要求。 JwtBearerHandler 會處理所有其他要求。 此外,此方法會向預設範圍為 <<ApplicationName>>API 的 IdentityServer 註冊 <<ApplicationName>>API API 資源,並設定 JWT 持有人權杖中介軟體來驗證應用程式 IdentityServer 所簽發的權杖。

WeatherForecastController

在檔案中,請注意套用至類別的 [Authorize] 屬性,指出使用者必須根據預設原則來存取資源。 預設授權原則會設定為使用預設驗證配置,此配置是由上述原則配置 AddIdentityServerJwt 所設定,使得這類協助程式方法所設定 JwtBearerHandler 應用程式要求的預設處理常式。

ApplicationDbContext

在檔案中,請注意 Identity 使用相同的 DbContext,但例外狀況是它會擴充 ApiAuthorizationDbContext (IdentityDbContext 的衍生類別),以包含 IdentityServer 的結構描述。

若要取得資料庫結構描述的完全控制權,請從其中一個可用的 IdentityDbContext 繼承,並透過在 OnModelCreating 方法上呼叫 builder.ConfigurePersistedGrantContext(_operationalStoreOptions.Value) 來將內容設定為包含 Identity 結構描述。

OidcConfigurationController

在檔案中,請注意佈建的端點,以提供用戶端需要使用的 OIDC 參數。

appsettings.json

在專案根目錄的 appsettings.json 檔案中,有一個新的 IdentityServer 區段描述已設定的用戶端清單。 在下列的範例中,有一個單一的用戶端。 用戶端名稱會對應至應用程式名稱,並依照慣例對應至 OAuth ClientId 參數。 設定檔指出正在設定的應用程式類型。 它會在內部用來驅動慣例,以簡化伺服器的設定處理過程。 有數個設定檔可供使用,如應用程式設定檔一節所述。

"IdentityServer": {
  "Clients": {
    "angularindividualpreview3final": {
      "Profile": "IdentityServerSPA"
    }
  }
}

appsettings.Development.json

在專案根目錄的 appsettings.Development.json 檔案中,有一個 IdentityServer 區段描述用來簽署權杖的金鑰。 部署至生產環境時,必須與應用程式一起布建和部署金鑰,如部署至生產一節所述。

"IdentityServer": {
  "Key": {
    "Type": "Development"
  }
}

Angular 應用程式的一般描述

Angular 範本中的驗證和 API 授權支援位於 ClientApp/src/API-authorization 目錄中自己的 Angular 模組中。 模組是由下列元素所組成:

  • 3 個元件:
    • login.component.ts:處理應用程式的登入流程。
    • logout.component.ts:處理應用程式的登出流程。
    • login-menu.component.ts:顯示下列其中一組連結的 Widget:
      • 使用者驗證時,使用者設定檔管理和登出連結。
      • 使用者未通過驗證時註冊和登入連結。
  • 路由保護 AuthorizeGuard 可以新增至路由,並要求使用者在瀏覽路由之前先進行驗證。
  • HTTP 攔截器 AuthorizeInterceptor,會在使用者通過驗證時,將存取權杖附加至以 API 為目標的傳出 HTTP 要求。
  • 服務 AuthorizeService 處理驗證過程的較低層級詳細資訊,並將有關經過驗證的用戶的資訊公開給應用程式的 rest 以供取用。
  • Angular 模組,定義與應用程式驗證部分相關聯的路由。 它會公開登入功能表元件、攔截器、保護和服務,以便從應用程式的 rest 取用。

React 應用程式的一般描述

React 範本中的驗證和 API 授權支援位於 ClientApp/src/components/api-authorization 目錄中。 它是由下列元素所組成:

  • 4 個元件:
    • Login.js:處理應用程式的登入流程。
    • Logout.js:處理應用程式的登出流程。
    • LoginMenu.js:顯示下列其中一組連結的 Widget:
      • 使用者驗證時,使用者設定檔管理和登出連結。
      • 使用者未通過驗證時註冊和登入連結。
    • AuthorizeRoute.js:在轉譯 Component 參數中所指示的元件之前,必須先驗證使用者的路由元件。
  • 類別 AuthorizeService 的匯出 authService 執行個體,用於處理驗證過程的較低層級詳細資訊,並將有關經過驗證的使用者的資訊公開給應用程式的 rest 以供取用。

既然您已了解解決方案的主要元件,您可以更深入地查看應用程式的個別情節。

需要新 API 的授權

根據預設,系統會設定為輕鬆要求新 API 的授權。 若要這樣做,請建立新的控制器,並將 [Authorize] 屬性新增至控制器類別或控制器內的任何動作。

自訂 API 驗證處理常式

若要自訂 API JWT 處理常式的組態,請設定其 JwtBearerOptions 執行個體:

services.AddAuthentication()
    .AddIdentityServerJwt();

services.Configure<JwtBearerOptions>(
    IdentityServerJwtConstants.IdentityServerJwtBearerScheme,
    options =>
    {
        ...
    });

API 的 JWT 處理常式會引發事件,以使用 JwtBearerEvents 啟用驗證程式的控制權。 若要提供 API 授權的支援,AddIdentityServerJwt 註冊自己的事件處理常式。

若要自訂事件的處理,請視需要以其他邏輯包裝現有的事件處理常式。 例如:

services.Configure<JwtBearerOptions>(
    IdentityServerJwtConstants.IdentityServerJwtBearerScheme,
    options =>
    {
        var onTokenValidated = options.Events.OnTokenValidated;       

        options.Events.OnTokenValidated = async context =>
        {
            await onTokenValidated(context);
            ...
        }
    });

在上述的程式碼中,OnTokenValidated 事件處理常式被自訂實作所取代。 此實作:

  1. 呼叫 API 授權支援所提供的原始實作。
  2. 執行自己的自訂邏輯。

保護用戶端路由 (Angular)

若要保護用戶端路由,請在設定路由時,將授權保護新增至要執行的保護清單來完成。 例如,您可以看到主要應用程式 Angular 模組內如何設定 fetch-data 路由:

RouterModule.forRoot([
  // ...
  { path: 'fetch-data', component: FetchDataComponent, canActivate: [AuthorizeGuard] },
])

請務必提及保護路由不會保護實際端點 (這仍然需要套用 [Authorize] 屬性),但只會防止使用者在未通過驗證時瀏覽至指定的用戶端路由。

驗證 API 要求 (Angular)

透過使用應用程式所定義的 HTTP 用戶端攔截器,自動驗證與應用程式一起裝載之 API 的要求。

保護用戶端路由 (React)

使用 AuthorizeRoute 元件而非純 Route 元件來保護用戶端路由。 例如,請注意如何在 App 元件內設定 fetch-data 路由:

<AuthorizeRoute path='/fetch-data' component={FetchData} />

保護路由:

  • 不會保護實際端點 (這仍然需要套用 [Authorize] 屬性)。
  • 只有在未通過驗證時,使用者才能瀏覽至指定的用戶端路由。

驗證 API 要求 (React)

使用 React 驗證要求是先從 AuthorizeService 匯入 authService 執行個體來完成。 存取權杖是從 authService 擷取,並附加至要求,如下所示。 在 React 元件中,這項工作通常是在 componentDidMount 生命週期方法中完成,或因為某些使用者互動而產生。

authService 匯入元件

import authService from './api-authorization/AuthorizeService'

擷取並附加存取權杖至回應

async populateWeatherData() {
  const token = await authService.getAccessToken();
  const response = await fetch('api/SampleData/WeatherForecasts', {
    headers: !token ? {} : { 'Authorization': `Bearer ${token}` }
  });
  const data = await response.json();
  this.setState({ forecasts: data, loading: false });
}

部署至生產位置

若要將應用程式部署至生產環境,必須佈建下列資源:

  • 用來儲存 Identity 使用者帳戶和 IdentityServer 授與的資料庫。
  • 用於簽署權杖的生產憑證。
    • 此憑證沒有特定需求;它可以是自我簽署憑證或透過 CA 授權單位佈建的憑證。
    • 它可透過 PowerShell 或 OpenSSL 等標準工具產生。
    • 它可以安裝在目的電腦上的憑證存放區中,或部署為具有強式密碼的 .pfx 檔案。

範例:部署至非 Azure Web 裝載提供者

在您的 Web 主控面板中,建立或載入您的憑證。 然後在應用程式的 appsettings.json 檔案中,修改 IdentityServer 區段以包含金鑰詳細資料。 例如:

"IdentityServer": {
  "Key": {
    "Type": "Store",
    "StoreName": "WebHosting",
    "StoreLocation": "CurrentUser",
    "Name": "CN=MyApplication"
  }
}

在前述範例中:

  • StoreName 代表儲存憑證的憑證存放區名稱。 在此情況下,它會指向 Web 裝載存放區。
  • StoreLocation 代表從何處載入憑證 (在此案例中為 CurrentUser)。
  • Name 對應至憑證的辨別主體。

範例:部署至 Azure App Service

本節說明如何使用儲存在憑證存放區中的憑證,將應用程式部署至 Azure App Service。 若要修改應用程式以從憑證存放區載入憑證,當您在稍後的步驟中設定 Azure 入口網站應用程式時,需要標準層服務方案或更好的方案。

在應用程式的 appsettings.json 檔案中,修改 IdentityServer 區段以包含金鑰詳細資料:

"IdentityServer": {
  "Key": {
    "Type": "Store",
    "StoreName": "My",
    "StoreLocation": "CurrentUser",
    "Name": "CN=MyApplication"
  }
}
  • 存放區名稱代表儲存憑證的憑證存放區名稱。 在此情況下,它會指向個人使用者存放區。
  • 存放區位置代表從 (CurrentUserLocalMachine) 載入憑證的位置。
  • 憑證上的 name 屬性會對應至憑證的辨別主體。

若要部署至 Azure App Service,請遵循將應用程式部署至 Azure 中的步驟,其中說明如何建立必要的 Azure 資源,並將應用程式部署至生產環境。

遵循上述指示之後,應用程式會部署至 Azure,但尚無法運作。 應用程式所使用的憑證必須在 Azure 入口網站中設定。 找出憑證的指紋,並遵循載入憑證中所述的步驟。

雖然這些步驟提到 SSL,但 Azure 入口網站中有私人憑證區段,您可以在其中上傳佈建的憑證以搭配應用程式使用。

在 Azure 入口網站中設定應用程式和應用程式的設定之後,請在入口網站中重新啟動應用程式。

其他組態選項

API 授權的支援建置在 IdentityServer 之上,其中包含一組慣例、預設值和增強功能,以簡化 SPA 的體驗。 不用說,如果 ASP.NET Core 整合未涵蓋您的案例,IdentityServer 的完整功能就會在幕後提供。 ASP.NET 核心支援著重於「第一方」應用程式,其中所有應用程式都是由我們的組織建立和部署。 因此,不支援同意或同盟等專案。 在這些案例中,請使用 IdentityServer 並遵循其文件。

應用程式設定檔

應用程式設定檔是進一步定義其參數之應用程式的預先定義組態。 目前支援下列設定檔:

  • IdentityServerSPA:代表託管於 IdentityServer 作為單一單位的 SPA。
    • redirect_uri 預設為 /authentication/login-callback
    • post_logout_redirect_uri 預設為 /authentication/logout-callback
    • 一組範圍包含 openidprofile 和針對應用程式中 API 所定義的每個範圍。
    • 允許的 OIDC 回應類型集是 id_token token 或每個單獨的回應類型 (id_token, token)。
    • 允許的回應模式為 fragment
  • SPA:代表未託管於 IdentityServe 的 SPA。
    • 一組範圍包含 openidprofile 和針對應用程式中 API 所定義的每個範圍。
    • 允許的 OIDC 回應類型集是 id_token token 或每個單獨的回應類型 (id_token, token)。
    • 允許的回應模式為 fragment
  • IdentityServerJwt:代表與 IdentityServe 一起託管的 API。
    • 應用程式設定為具有預設為應用程式名稱的單一範圍。
  • API:代表未託管於 IdentityServer 的 API。
    • 應用程式設定為具有預設為應用程式名稱的單一範圍。

透過 AppSettings 設定

透過組態系統設定應用程式,方法是將它們新增至 ClientsResources 清單。

設定每個用戶端的 redirect_uripost_logout_redirect_uri 屬性,如下列範例所示:

"IdentityServer": {
  "Clients": {
    "MySPA": {
      "Profile": "SPA",
      "RedirectUri": "https://www.example.com/authentication/login-callback",
      "LogoutUri": "https://www.example.com/authentication/logout-callback"
    }
  }
}

設定資源時,您可以設定資源的範圍,如下所示:

"IdentityServer": {
  "Resources": {
    "MyExternalApi": {
      "Profile": "API",
      "Scopes": "a b c"
    }
  }
}

透過程式碼設定

您也可以透過使用多載 AddApiAuthorization 的程式碼來設定用戶端和資源,以採取動作來設定選項。

AddApiAuthorization<ApplicationUser, ApplicationDbContext>(options =>
{
    options.Clients.AddSPA(
        "My SPA", spa =>
        spa.WithRedirectUri("http://www.example.com/authentication/login-callback")
           .WithLogoutRedirectUri(
               "http://www.example.com/authentication/logout-callback"));

    options.ApiResources.AddApiResource("MyExternalApi", resource =>
        resource.WithScopes("a", "b", "c"));
});

其他資源