驗證和授權

提示

本內容節錄自《Enterprise Application Patterns Using .NET MAUI》電子書,可以從 .NET Docs 取得,也可以免費下載 PDF 離線閱讀。

Enterprise Application Patterns Using .NET MAUI eBook cover thumbnail.

驗證是取得使用者名稱和密碼等識別認證,並根據授權單位驗證這些認證的流程。 如果認證有效,則提交認證的實體即視為通過身分識別驗證。 建立身分識別之後,授權處理流程會判斷該身分識別是否有權存取指定的資源。

有許多方法可將驗證和授權整合為一個 .NET MAUI 應用程式,與 ASP.NET Web 應用程式通訊,包括使用 ASP.NET Core 身分識別、外部驗證提供者 (例如 Microsoft、Google、Facebook 或 Twitter) 以及驗證中介軟體。 eShopOnContainers 多平台應用程式會使用運用 IdentityServer 4 的容器化身分識別微服務執行驗證和授權。 應用程式會向 IdentityServer 要求安全性權杖,以驗證使用者或存取資源。 使用者必須登入 IdentityServer,才能讓 IdentityServer 代使用者核發權杖。 不過,IdentityServer 不提供使用者介面或資料庫以供驗證。 因此,在 eShopOnContainers 參考應用程式中,ASP.NET Core 身分識別即作此用。

驗證

當應用程式需要知道目前使用者的身分識別時,即需要驗證。 ASP.NET Core 識別使用者的主要機制是 ASP.NET Core 身分識別成員資格系統,其會將使用者資訊儲存在開發人員所設定的資料存放區中。 一般而言,此資料存放區會是 EntityFramework 存放區,但還是可以使用自訂存放區或協力廠商套件將身分識別資訊儲存在 Azure 儲存體、DocumentDB 或其他位置。

至於使用本機使用者資料存放區,以及透過 Cookie 保存要求與要求間身分識別資訊 (這在 ASP.NET 應用程式中很普遍) 的驗證案例,ASP.NET Core 身分識別是合適的解決方案。 不過,Cookie 不一定是保存及傳輸資料的自然方式。 例如,公開從應用程式存取之 RESTful 端點的 ASP.NET Core Web 應用程式,通常需要使用持有人權杖驗證,因為這種情況下無法使用 Cookie。 不過,持有人權杖很容易擷取,而且可包含在應用程式發出之 Web 要求的授權標頭中。

使用 IdentityServer 4 核發持有人權杖

IdentityServer 4 是開放原始碼 OpenID Connect 和適用於 ASP.NET Core 的 OAuth 2.0 架構,可用於許多驗證和授權案例,包括核發本機 ASP.NET Core 身分識別使用者的安全性權杖。

注意

OpenID Connect 和 OAuth 2.0 非常類似,但職責不同。

OpenID Connect 是 OAuth 2.0 通訊協定最上層的驗證層。 OAuth 2 是一種通訊協定,可讓應用程式向安全性權杖服務要求存取權杖,並使用它們與 API 通訊。 這種委派可減少用戶端應用程式和 API 的複雜性,因為驗證和授權可以集中化。

OpenID Connect 和 OAuth 2.0 結合了驗證和 API 存取的兩個基本安全性考慮,而 IdentityServer 4 則是這些通訊協定的實作。

在使用直接用戶端對微服務通訊的應用程式中,例如 eShopOnContainers 參考應用程式,作用如同 Security Token Service (STS) 的專用驗證微服務可用來驗證使用者,如下圖所示。 如需直接用戶端對微服務通訊的詳細資訊,請參閱微服務

Authentication by a dedicated authentication microservice.

eShopOnContainers 多平台應用程式會與使用 IdentityServer 4 的身分識別微服務通訊,以執行驗證和 API 的存取控制。 因此,多平台應用程式會向 IdentityServer 要求權杖,以驗證使用者或存取資源:

  • 以 IdentityServer 驗證使用者是經由多平台應用程式要求身分識別權杖而達成,代表驗證流程的結果。 至少包含使用者識別碼,以及使用者驗證方式和時間的相關資訊。 也可以包含其他的身分識別資料。
  • 以 IdentityServer 存取資源是經由多平台應用程式要求存取權杖而達成,其允許存取 API 資源。 用戶端會要求存取權杖,並將其轉送至 API。 存取權杖包含用戶端和使用者的相關資訊 (如有)。 然後,API 會使用該資訊授權,准許存取其資料。

注意

用戶端必須先向 IdentityServer 註冊,才能成功要求權杖。 如需新增用戶端的詳細資訊,請參閱定義用戶端

將 IdentityServer 新增至 Web 應用程式

為了讓 ASP.NET Core Web 應用程式使用 IdentityServer 4,後者必須新增至 Web 應用程式的 Visual Studio 解決方案。 如需詳細資訊,請參閱 IdentityServer 文件中的安裝和概觀。 IdentityServer 一旦包含在 Web 應用程式的 Visual Studio 解決方案中,就必須新增至其 HTTP 要求處理管線,以處理 OpenID Connect 和 OAuth 2.0 端點的要求。 這可在 Web 應用程式之 Startup 類別的 Configure 方法中達成,如下列程式碼範例所示:

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory)
{
    app.UseIdentity();
}

Web 應用程式之 HTTP 要求處理管線中的順序至關重要。 因此,IdentityServer 新增至管線的順序,必須在實作登入畫面的 UI 架構之前。

設定 IdentityServer

IdentityServer 應透過呼叫 services.AddIdentityServer 方法,在 Web 應用程式之 Startup 類別的 ConfigureServices 方法中設定,如下列 eShopOnContainers 參考應用程式的程式碼範例所示:

public void ConfigureServices(IServiceCollection services)
{
    services
        .AddIdentityServer(x => x.IssuerUri = "null")
        .AddSigningCredential(Certificate.Get())
        .AddAspNetIdentity<ApplicationUser>()
        .AddConfigurationStore(builder =>
            builder.UseSqlServer(connectionString, options =>
                options.MigrationsAssembly(migrationsAssembly)))
        .AddOperationalStore(builder =>
            builder.UseSqlServer(connectionString, options =>
                options.MigrationsAssembly(migrationsAssembly)))
        .Services.AddTransient<IProfileService, ProfileService>();
}

呼叫 services.AddIdentityServer 方法之後,還會呼叫其他 Fluent API 來設定下列項目:

  • 用於登入的認證。
  • 使用者可能要求存取的 API 和身分識別資源。
  • 要連線要求權杖的用戶端。
  • ASP.NET Core 身分識別。

提示

動態載入 IdentityServer 4 組態。 IdentityServer 4 的 API 允許從記憶體內的組態物件清單中設定 IdentityServer。 在 eShopOnContainers 參考應用程式中,這些記憶體內集合會硬式編碼到應用程式中。 不過,在生產案例中,其可以從組態檔或資料庫動態載入。

如需將 IdentityServer 設定為使用 ASP.NET Core 身分識別的相關資訊,請參閱 IdentityServer 文件中的使用 ASP.NET Core 身分識別

設定 API 資源

設定 API 資源時,AddInMemoryApiResources 方法預期有 IEnumerable<ApiResource> 集合。 下列程式碼範例示範的 GetApis 方法,會在 eShopOnContainers 參考應用程式中提供此集合:

public static IEnumerable<ApiResource> GetApis()
{
    return new List<ApiResource>
    {
        new ApiResource("orders", "Orders Service"),
        new ApiResource("basket", "Basket Service")
    };
}

這個方法指定 IdentityServer 應該保護訂單和購物籃 API。 因此,呼叫這些 API 時,需要有受 IdentityServer 管理的存取權杖。 如需 ApiResource 類型的詳細資訊,請參閱 IdentityServer 4 文件中的 API 資源

設定身分識別資源

設定身分識別資源時,AddInMemoryIdentityResources 方法預期有 IEnumerable<IdentityResource> 集合。 身分識別資源是使用者識別碼、名稱或電子郵件地址等資料。 每種身分識別資源都有唯一的名稱,而且可被指派任意宣告類型,包含在使用者的身分識別權杖中。 下列程式碼範例示範的 GetResources 方法,會在 eShopOnContainers 參考應用程式中提供此集合:

public static IEnumerable<IdentityResource> GetResources()
{
    return new List<IdentityResource>
    {
        new IdentityResources.OpenId(),
        new IdentityResources.Profile()
    };
}

OpenID Connect 規格會指定一些標準身分識別資源。 最低需求是支援發出使用者的唯一識別碼。 公開 IdentityResources.OpenId 身分識別資源即可達成此目的。

注意

IdentityResources 類別支援 OpenID Connect 規格中定義的所有範圍 (openid、電子郵件、設定檔、電話和地址)。

IdentityServer 也支援定義自訂的身分識別資源。 如需詳細資訊,請參閱 IdentityServer 文件中的定義自訂的身分識別資源。 如需 IdentityResource 類型的詳細資訊,請參閱 IdentityServer 4 文件中的身分識別資源

設定用戶端

用戶端是可向 IdentityServer 要求權杖的應用程式。 一般而言,每個用戶端至少都必須定義下列設定:

  • 唯一的用戶端識別碼。
  • 允許與權杖服務的互動 (稱為授與類型)。
  • 身分識別和存取權杖傳送目的地位置 (稱為重新導向 URI)。
  • 允許用戶端存取的資源清單 (稱為範圍)。

設定用戶端時,AddInMemoryClients 方法預期有 IEnumerable<Client> 集合。 下列程式碼範例示範如何使用在 eShopOnContainers 參考應用程式中提供此集合的 GetClients 方法,顯示 eShopOnContainers 多平台應用程式的組態:

public static IEnumerable<Client> GetClients(Dictionary<string,string> clientsUrl)
{
    return new List<Client>
    {
        // Omitted for brevity
        new Client
        {
            ClientId = "xamarin",
            ClientName = "eShop Xamarin OpenId Client",
            AllowedGrantTypes = GrantTypes.Hybrid,
            ClientSecrets =
            {
                new Secret("secret".Sha256())
            },
            RedirectUris = { clientsUrl["Xamarin"] },
            RequireConsent = false,
            RequirePkce = true,
            PostLogoutRedirectUris = { $"{clientsUrl["Xamarin"]}/Account/Redirecting" },
            AllowedCorsOrigins = { "http://eshopxamarin" },
            AllowedScopes = new List<string>
            {
                IdentityServerConstants.StandardScopes.OpenId,
                IdentityServerConstants.StandardScopes.Profile,
                IdentityServerConstants.StandardScopes.OfflineAccess,
                "orders",
                "basket"
            },
            AllowOfflineAccess = true,
            AllowAccessTokensViaBrowser = true
        },
    };
}

此組態會指定下列屬性的資料:

屬性 說明
ClientId 用戶端的唯一識別碼。
ClientName 用戶端顯示名稱,用於記錄和同意畫面。
AllowedGrantTypes 指定用戶端如何與 IdentityServer 互動。 如需詳細資訊,請參閱設定驗證流程
ClientSecrets 指定向權杖端點要求權杖時所使用的用戶端密碼認證。
RedirectUris 指定允許接受傳回權杖或授權碼的 URI。
RequireConsent 指定是否需要同意畫面。
RequirePkce 指定使用授權碼的用戶端是否必須傳送證明金鑰。
PostLogoutRedirectUris 指定登出後允許重新導向至的 URI。
AllowedCorsOrigins 指定用戶端原點,讓 IdentityServer 得以允許來自原點的跨原點呼叫。
AllowedScopes 指定用戶端有權存取的資源。 用戶端預設無權存取任何資源。
AllowOfflineAccess 指定用戶端是否可以要求重新整理權杖。

設定驗證流程

用戶端與 IdentityServer 之間的驗證流程可透過在 Client.AllowedGrantTypes 屬性中指定授與類型來設定。 OpenID Connect 和 OAuth 2.0 規格會定義數個驗證流程,包括:

驗證流程 描述
隱式 此流程已針對瀏覽器型應用程式最佳化,應僅限使用者驗證之用,或要求驗證和存取權杖之用。 所有權杖都會透過瀏覽器傳輸,因此不允許重新整理權杖等進階功能。
授權碼 此流程可讓您在後端通道擷取權杖,而不是瀏覽器前端通道,同時還支援用戶端驗證。
混合式 此流程是隱含和授權碼授與類型的組合。 身分識別權杖會透過瀏覽器通道傳輸,並包含已簽署的通訊協定回應和其他成品,例如授權碼。 成功驗證回應之後,應可使用後端通道擷取存取權杖和重新整理權杖。

提示

請考慮使用混合式驗證流程。 混合式驗證流程可減輕對瀏覽器通道的大量攻擊,而且是適合想要擷取存取權杖 (且可能是重新整理權杖) 之原生應用程式的建議流程。

如需驗證流程的詳細資訊,請參閱 IdentityServer 4 文件中的授與類型

執行驗證

使用者必須登入 IdentityServer,才能讓 IdentityServer 代使用者核發權杖。 不過,IdentityServer 不提供使用者介面或資料庫以供驗證。 因此,在 eShopOnContainers 參考應用程式中,ASP.NET Core 身分識別即作此用。

eShopOnContainers 多平台應用程式會使用混合式驗證流程向 IdentityServer 驗證,如下圖所示。

High-level overview of the sign in process.

<base endpoint>:5105/connect/authorize 提出登入要求。 成功驗證之後,IdentityServer 會傳回包含授權碼和身分識別權杖的驗證回應。 授權碼會傳送至 <base endpoint>:5105/connect/token,以存取權杖、身分識別權杖和重新整理權杖回應。

eShopOnContainers 多平台應用程式會向 <base endpoint>:5105/connect/endsession 傳送要求及其他參數,以登出 IdentityServer。 登出之後,IdentityServer 的回應方式,是將登出後重新導向的 URI 傳送回多平臺應用程式。 下圖說明此流程。

High-level overview of the sign out process.

在 eShopOnContainers 多平台應用程式中,與 IdentityServer 的通訊是由實作 IIdentityService 介面的 IdentityService 類別執行。 此介面會指定實作類別必須提供 CreateAuthorizationRequestCreateLogoutRequestGetTokenAsync 方法。

登入

當使用者點選 LoginView 上的 LOGIN 按鈕時,會執行 LoginViewModel 類別中的 SignInCommand,接著執行 SignInAsync 方法。 下列程式碼範例示範此方法:

private async Task SignInAsync()
{
    await IsBusyFor(
        async () =>
        {
            LoginUrl = _identityService.CreateAuthorizationRequest();

            IsValid = true;
            IsLogin = true;
        });
}

這個方法會叫用 IdentityService 類別中的 CreateAuthorizationRequest 方法,如下列程式碼範例所示:

public string CreateAuthorizationRequest()
{
    // Create URI to authorization endpoint
    var authorizeRequest = new AuthorizeRequest(GlobalSetting.Instance.IdentityEndpoint);
    // Dictionary with values for the authorize request
    var dic = new Dictionary<string, string>();
    dic.Add("client_id", GlobalSetting.Instance.ClientId);
    dic.Add("client_secret", GlobalSetting.Instance.ClientSecret); 
    dic.Add("response_type", "code id_token");
    dic.Add("scope", "openid profile basket orders locations marketing offline_access");
    dic.Add("redirect_uri", GlobalSetting.Instance.IdentityCallback);
    dic.Add("nonce", Guid.NewGuid().ToString("N"));
    dic.Add("code_challenge", CreateCodeChallenge());
    dic.Add("code_challenge_method", "S256");
    // Add CSRF token to protect against cross-site request forgery attacks.
    var currentCSRFToken = Guid.NewGuid().ToString("N");
    dic.Add("state", currentCSRFToken);
    
    var authorizeUri = authorizeRequest.Create(dic); 
    return authorizeUri;
}

這個方法會使用必要的參數,建立 IdentityServer 授權端點 的 URI。 授權端點位於公開為使用者設定之基底端點連接埠 5105 的 /connect/authorize。 如需使用者設定的詳細資訊,請參閱組態管理

注意

實作 OAuth 的 Proof Key for Code Exchange (PKCE) 延伸模組以減少 eShopOnContainers 多平台應用程式的受攻擊面。 PKCE 可阻擋使用被攔截的授權碼。 這是由產生祕密驗證器的用戶端所達成,在授權要求中以雜湊方式傳遞,在兌換授權碼時顯示為未隱藏。 如需 PKCE 的詳細資訊,請參閱網際網路工程任務推動小組網站上的 OAuth 公用用戶端的 Proof Key for Code Exchange (英文)。

傳回的 URI 會儲存在 LoginViewModel 類別的 LoginUrl 屬性中。 當 IsLogin 屬性變成 true 時,LoginView 中的 WebView 會變成可見。 當 LoginUrl 屬性設定為 IdentityServer 的授權端點時,WebView 資料會將自己的 Source 屬性繫結至 LoginViewModel 類別的 LoginUrl 屬性,並將登入要求繫結至 IdentityServer。 當 IdentityServer 收到此要求但使用者未通過驗證時,WebView 將會被重新導向至設定的登入頁面,如下圖所示。

Login page displayed by the WebView.

登入完成後,WebView 會被重新導向至傳回 URI。 此 WebView 導覽會導致執行 LoginViewModel 類別中的 NavigateAsync 方法,如下列程式碼範例所示:

private async Task NavigateAsync(string url)
{
    var unescapedUrl = System.Net.WebUtility.UrlDecode(url);

    if (unescapedUrl.Equals(GlobalSetting.Instance.LogoutCallback, StringComparison.OrdinalIgnoreCase))
    {
        _settingsService.AuthAccessToken = string.Empty;
        _settingsService.AuthIdToken = string.Empty;
        IsLogin = false;
        LoginUrl = _identityService.CreateAuthorizationRequest();
    }
    else if (unescapedUrl.Contains(GlobalSetting.Instance.Callback, StringComparison.OrdinalIgnoreCase))
    {
        var authResponse = new AuthorizeResponse(url);
        if (!string.IsNullOrWhiteSpace(authResponse.Code))
        {
            var userToken = await _identityService.GetTokenAsync(authResponse.Code);
            string accessToken = userToken.AccessToken;

            if (!string.IsNullOrWhiteSpace(accessToken))
            {
                _settingsService.AuthAccessToken = accessToken;
                _settingsService.AuthIdToken = authResponse.IdentityToken;
                await NavigationService.NavigateToAsync("//Main/Catalog");
            }
        }
    }
}

此方法會剖析包含在傳回 URI 中的驗證回應,如有有效的授權碼,就會向 IdentityServer 的權杖端點提出要求,傳遞授權碼、PKCE 祕密驗證器和其他必要參數。 權杖端點位於公開為使用者設定之基底端點連接埠 5105 的 /connect/token。 如需使用者設定的詳細資訊,請參閱組態管理)。

提示

請務必驗證傳回 URI。 雖然 eShopOnContainers 多平台應用程式不會驗證傳回 URI,但最佳做法是驗證傳回 URI 是否參考已知的位置,以防止開放重新導向攻擊。

如果權杖端點收到有效的授權碼和 PKCE 秘密驗證器,則會使用存取權杖、身分識別權杖和重新整理權杖來回應。 存取權杖 (允許存取 API 資源) 和身分識別權杖會儲存為應用程式設定,並執行頁面導覽。 因此,eShopOnContainers 多平台應用程式的整體效果如是:假設使用者能夠成功向 IdentityServer 驗證,就可以被導覽至 //Main/Catalog 路由,亦即將 CatalogView 顯示為所選索引標籤的 TabbedPage

如需頁面導覽的相關資訊,請參閱導覽。 如需 WebView 導覽如何導致檢視模型方法執行的相關資訊,請參閱使用行為叫用導覽。 如需應用程式設定的相關資訊,請參閱組態管理

注意

當應用程式設定為使用 SettingsView 的模擬服務時,eShopOnContainers 也允許模擬登入。 在此模式中,應用程式不會與 IdentityServer 通訊,而是允許使用者使用任何認證登入。

登出

當使用者點選 ProfileView 上的 LOG OUT 按鈕時,會執行 ProfileViewModel 類別中的 LogoutCommand,這會執行 LogoutAsync 方法。 這個方法會將頁面導覽至 LoginView 頁面,並將設為 trueLogoutParameter 執行個體當做參數傳遞。

建立並導覽至檢視時,會執行與檢視模型相關聯的檢視 InitializeAsync 方法,然後執行 LoginViewModel 類別的 Logout 方法,如下列程式碼範例所示:

private void Logout()
{
    var authIdToken = Settings.AuthIdToken;
    var logoutRequest = _identityService.CreateLogoutRequest(authIdToken);

    if (!string.IsNullOrEmpty(logoutRequest))
    {
        // Logout
        LoginUrl = logoutRequest;
    }
    
    // Omitted for brevity
}

這個方法會叫用 IdentityService 類別中的 CreateLogoutRequest 方法,將擷取自應用程式設定的身分識別權杖當做參數傳遞。 如需應用程式設定的詳細資訊,請參閱組態管理。 下列程式碼範例示範 CreateLogoutRequest 方法:

public string CreateLogoutRequest(string token)
{
    // Omitted for brevity

    var (endpoint, callback) =
        (GlobalSetting.Instance.LogoutEndpoint, GlobalSetting.Instance.LogoutCallback);

    return $"{endpoint}?id_token_hint={token}&post_logout_redirect_uri={callback}";
}

這個方法會使用必要的參數,建立 IdentityServer 結束工作階段端點的 URI。 結束工作階段端點位於公開為使用者設定之基底端點連接埠 5105 的 /connect/endsession

傳回的 URI 會儲存在 LoginViewModel 類別的 LoginUrl 屬性中。 當 IsLogin 屬性為 true 時,會顯示 LoginView 中的 WebView。 當 LoginUrl 屬性設定為 IdentityServer 的結束工作階段端點時,WebView 資料會將自己的 Source 屬性繫結至 LoginViewModel 類別的 LoginUrl 屬性,並向 IdentityServer 提出登出要求。 假設使用者此時為登入狀態,當 IdentityServer 收到此要求時就會執行登出。 由 ASP.NET Core 之 Cookie 驗證中介軟體所管理的 Cookie 會追蹤驗證。 因此,登出 IdentityServer 會移除驗證 Cookie,並將登出後重新導向 URI 傳送回用戶端。

WebView 會被重新導向至多平台應用程式的登出後重新導向 URI。 此 WebView 導覽會導致執行 LoginViewModel 類別中的 NavigateAsync 方法,如下列程式碼範例所示:

private async Task NavigateAsync(string url)
{
    var unescapedUrl = System.Net.WebUtility.UrlDecode(url);

    if (unescapedUrl.Equals(GlobalSetting.Instance.LogoutCallback, StringComparison.OrdinalIgnoreCase))
    {
        _settingsService.AuthAccessToken = string.Empty;
        _settingsService.AuthIdToken = string.Empty;
        IsLogin = false;
        LoginUrl = _identityService.CreateAuthorizationRequest();
    }
    
    // Omitted for brevity
}

此方法會清除應用程式設定中的身分識別權杖和存取權杖。 它會將 IsLogin 屬性設定為 false,導致 LoginView 頁面上的 WebView 變成不可見。 最後,LoginUrl 屬性會被設為 IdentityServer 授權端點的 URI,其中包含必要的參數,以備下次使用者起始登入時使用。

如需頁面導覽的相關資訊,請參閱導覽。 如需 WebView 導覽如何導致檢視模型方法執行的相關資訊,請參閱使用行為叫用導覽。 如需應用程式設定的相關資訊,請參閱組態管理

注意

當應用程式設定為使用 SettingsView 的模擬服務時,eShopOnContainers 也允許模擬登出。 在此模式中,應用程式不會與 IdentityServer 通訊,而是清除應用程式設定中所有已儲存的權杖。

授權

驗證之後,ASP.NET Core Web API 通常需要授權存取權,讓服務將 API 提供給某些已通過驗證的使用者,但並非提供給所有使用者。

將 Authorize 屬性套用至控制器或動作,以限制已通過驗證使用者對控制器或動作的存取,可以限制對 ASP.NET Core 路由的存取,如下列程式碼範例所示:

[Authorize]
public sealed class BasketController : Controller
{
    // Omitted for brevity
}

如果未經授權的使用者嘗試存取標記了 Authorize 屬性的控制器或動作,API 架構會傳回 401 (unauthorized) HTTP 狀態碼。

注意

您可以在 Authorize 屬性中指定參數,限制僅特定使用者可使用 API。 如需詳細資訊,請參閱 ASP.NET Core 文件:授權

IdentityServer 可以整合到授權工作流程中,以便其提供的存取權杖可控制授權。 此方法如下圖所示。

Authorization by access token.

eShopOnContainers 多平台應用程式會與身分識別微服務通訊,並在驗證過程中要求存取權杖。 接著,存取權杖會隨著存取要求,被轉送到訂購和購物籃微服務公開的 API。 存取權杖包含用戶端和使用者的相關資訊。 然後,API 會使用該資訊授權,准許存取其資料。 如需如何設定 IdentityServer 以保護 API 的相關資訊,請參閱設定 API 資源

設定 IdentityServer 以執行授權

若要使用 IdentityServer 執行授權,您必須將其授權中介軟體新增至 Web 應用程式的 HTTP 要求管線。 中介軟體會新增至 Web 應用程式的 Startup 類別中的 ConfigureAuth 方法,從 Configure 方法叫用,並以 eShopOnContainers 參考應用程式的下列程式碼範例示範:

protected virtual void ConfigureAuth(IApplicationBuilder app)
{
    var identityUrl = Configuration.GetValue<string>("IdentityUrl");
    app.UseIdentityServerAuthentication(new IdentityServerAuthenticationOptions
    {
        Authority = identityUrl.ToString(),
        ScopeName = "basket",
        RequireHttpsMetadata = false,
    });
}

此方法可確保唯有有效的存取權杖才能存取 API。 中介軟體會驗證傳入權杖,以確保其來自受信任的簽發者,並驗證權杖是否有效,得以與接收權杖的 API 搭配使用。 因此,瀏覽至訂購或購物籃控制器會傳回 401 (unauthorized) HTTP 狀態碼,指出需要有存取權杖。

注意

IdentityServer 的授權中介軟體必須先新增至 Web 應用程式的 HTTP 要求管線,才能使用 app.UseMvc()app.UseMvcWithDefaultRoute() 新增 MVC。

向 API 提出存取要求

向訂購和購物籃微服務提出要求時,要求中必須包含在驗證過程中自 IdentityServer 取得的存取權杖,如下列程式碼範例所示:

var authToken = Settings.AuthAccessToken;
Order = await _ordersService.GetOrderAsync(order.OrderNumber, authToken);

存取權杖會儲存為應用程式設定,並擷取自平台特定的儲存體,包含在對 OrderService 類別之 GetOrderAsync 方法的呼叫中。

同樣地,將資料傳送至 IdentityServer 保護的 API 時,也必須包含存取權杖,如下列程式碼範例所示:

var authToken = Settings.AuthAccessToken;
await _basketService.UpdateBasketAsync(
    new CustomerBasket
    {
        BuyerId = userInfo.UserId, 
        Items = BasketItems.ToList()
    }, 
    authToken);

存取權杖是從設定中擷取,並包含在對 BasketService 類別之 UpdateBasketAsync 方法的呼叫中。

eShopOnContainers 多平台應用程式中的 RequestProvider 類別會使用 HttpClient 類別向 eShopOnContainers 參考應用程式所公開的 RESTful API 提出要求。 向需要授權的訂購和購物籃 API 提出要求時,要求中必須包含有效的存取權杖。 將存取權杖新增至 HttpClient 執行個體的標頭即可達到此目的,如下列程式碼範例所示:

httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", token);

HttpClient 類別的 DefaultRequestHeaders 屬性會公開隨每個要求一起傳送的標頭,而存取權杖則會新增至以字串 Bearer 為前置詞的 Authorization 標頭。 當要求傳送到 RESTful API 後,會擷取並驗證 Authorization 標頭的值,以確保其是從信任的簽發者傳送,並用以判斷使用者是否有權叫用接收它的 API。

如需 eShopOnContainers 多平台應用程式如何提出 Web 要求的詳細資訊,請參閱存取遠端資料

摘要

有許多方法可將驗證和授權整合到 .NET MAUI 應用程式,與 ASP.NET Web 應用程式通訊。 eShopOnContainers 多平台應用程式會使用運用 IdentityServer 4 的容器化身分識別微服務執行驗證和授權。 IdentityServer 是開放原始碼 OpenID Connect 和適用於 ASP.NET Core 的 OAuth 2.0 架構,可與 ASP.NET Core 身分識別整合,以執行持有人權杖驗證。

多平台應用程式會向 IdentityServer 要求安全性權杖,以驗證使用者或存取資源。 存取資源時,需要授權之 API 的要求中必須包含存取權杖。 IdentityServer 的中介軟體會驗證傳入存取權杖,以確保它們是從受信任的簽發者傳送且有效,可與接收權杖的 API 搭配使用。