在 ASP.NET Core 中設定 OpenID Connect Web (UI) 驗證
本文涵蓋下列主題:
- 什麼是OpenID Connect機密互動式用戶端
- 在 ASP.NET Core 中建立 OpenID Connect 用戶端
- OpenID Connect 用戶端與代碼段的範例
- 使用第三方 OpenID Connect 提供者用戶端
- 前端的後端 (BFF) 安全性架構
- 進階功能、標準、擴充OpenID Connect用戶端
如需使用適用於 .NET的
如需使用 Microsoft Entra External ID OIDC 伺服器的範例,請參閱
什麼是OpenID Connect機密互動式用戶端
OpenID Connect 可用來在 ASP.NET Core 應用程式中實作驗證。 建議的方法是使用使用程式碼流程的OpenID Connect機密用戶端。 建議針對此實作使用 OAuth 公用用戶端的程式代碼交換證明密鑰(PKCE)。 應用程式用戶端和應用程式的用戶都會在機密流程中驗證。 應用程式用戶端會使用客戶端密碼或客戶端判斷提示進行驗證。
Web 應用程式不再建議使用公用 OpenID Connect/OAuth 用戶端。
預設流程的運作方式如下圖所示:
OpenID Connect 有許多變化,而且所有伺服器實作都有稍微不同的參數和需求。 有些伺服器不支援使用者資訊端點,有些伺服器仍然不支援 PKCE,有些則要求令牌要求中需要特殊參數。 您可以使用客戶端判斷提示,而不是客戶端密碼。 新的標準也存在,在 OpenID Connect Core 之上新增額外的安全性,例如 FAPI、CIBA 或下游 API 的 DPoP。
注意
從 .NET 9, 如果 OpenID Connect 伺服器支援,則預設會使用 OAuth 2.0 推送授權要求 (PAR) RFC 9126 。 這是三個步驟流程,而不是如上所示的兩個步驟流程。 (使用者資訊要求是選擇性步驟。
使用 Razor Pages 建立 Open ID Connect 程式代碼流程用戶端
下一節說明如何在空白的 ASP.NET Core Razor 頁面項目中實作 OpenID Connect 用戶端。 相同的邏輯可以套用至任何 ASP.NET Core Web 專案,只有 UI 整合不同。
新增 OpenID Connect 支援
將 Microsoft.AspNetCore.Authentication.OpenIdConnect
Nuget 套件新增至 ASP.NET Core 專案。
設定 OpenID Connect 用戶端
在 Program.cs
檔案中使用 builder.Services 將驗證新增至 Web 應用程式。 組態相依於 OpenID Connect 伺服器。 每個 OpenID Connect 伺服器都需要設定中的小差異。
OpenID Connect 處理程式用於挑戰和註銷。 cookie用來處理 Web 應用程式中的工作階段。 您可以視需要指定驗證的預設配置。
如需詳細資訊,請參閱 ASP.NET Core authentication-handler
指引。
builder.Services.AddAuthentication(options =>
{
options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
})
.AddCookie()
.AddOpenIdConnect(options =>
{
var oidcConfig = builder.Configuration.GetSection("OpenIDConnectSettings");
options.Authority = oidcConfig["Authority"];
options.ClientId = oidcConfig["ClientId"];
options.ClientSecret = oidcConfig["ClientSecret"];
options.SignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.ResponseType = OpenIdConnectResponseType.Code;
options.SaveTokens = true;
options.GetClaimsFromUserInfoEndpoint = true;
options.MapInboundClaims = false;
options.TokenValidationParameters.NameClaimType = JwtRegisteredClaimNames.Name;
options.TokenValidationParameters.RoleClaimType = "roles";
});
如需各種不同的 OpenID Connect 選項的詳細資訊,請參閱 使用 OpenID Connect 保護 ASP.NET Core Blazor Web App。
如需不同的宣告對應可能性,請參閱 ASP.NET Core 中的宣告對應、自定義和轉換。
注意
需要下列命名空間:
using Microsoft.AspNetCore.Authentication.Cookies;
using Microsoft.AspNetCore.Authentication.OpenIdConnect;
using Microsoft.IdentityModel.Protocols.OpenIdConnect;
using Microsoft.IdentityModel.Tokens;
設定組態屬性
將 OpenID Connect 用戶端設定新增至應用程式組態屬性。 這些設定必須符合 OpenID Connect 伺服器中的用戶端組態。 應用程式設定中不應保存秘密,因為應用程式設定可能會不小心簽入這些秘密。 秘密應該儲存在安全的位置,例如在生產環境中或開發環境中的使用者秘密中,例如 Azure 金鑰保存庫。 如需詳細資訊,請參閱 ASP.NET Core中開發的應用程式秘密安全儲存。
"OpenIDConnectSettings": {
// OpenID Connect URL. (The base URL for the /.well-known/openid-configuration)
"Authority": "<Authority>",
// client ID from the OpenID Connect server
"ClientId": "<Client ID>",
//"ClientSecret": "--stored-in-user-secrets-or-key-vault--"
},
登出回調路徑設定
SignedOutCallbackPath (組態索引鍵: “SignedOutCallbackPath
”) 是 OpenID Connect 處理程式在應用程式基底路徑內攔截的請求路徑,其中用戶代理在從身份提供者註銷後會先被重定向至此。 範例應用程式不會設定路徑的值,因為會使用預設值 「/signout-callback-oidc
」。。 攔截要求之後,如果指定,OpenID Connect 處理程式會重新導向至 SignedOutRedirectUri 或 RedirectUri。
在應用程式的 OIDC 提供者註冊中設定登出的回呼路徑。 在下列範例中,{PORT}
佔位符是應用程式的端口:
https://localhost:{PORT}/signout-callback-oidc
注意
使用 Microsoft Entra ID 時,請在 Entra 或 Azure 入口網站中的 Web 平台配置的 重新導向 URI 項目中設定路徑。 使用 Entra 時,localhost
位址不需要埠。 大多數其他 OIDC 提供者都需要正確的埠。 如果您未將登出後的回呼路徑 URI 新增至 Entra 中應用程式的註冊,Entra 會拒絕將使用者重新導向回應用程式,而僅要求他們關閉瀏覽器視窗。
更新程序類別中的 ASP.NET Core 管線方法。
必須先實作 UseRouting
方法,再實作 UseAuthorization
方法。
app.UseHttpsRedirection();
app.UseStaticFiles();
app.UseRouting();
app.UseAuthentication();
// Authorization is applied for middleware after the UseAuthorization method
app.UseAuthorization();
app.MapRazorPages();
強制授權
將 [Authorize]
屬性 新增至受保護的 Razor 頁面:
[Authorize]
更好的方法是強制授權整個應用程式,並為不安全的頁面選擇不授權。
var requireAuthPolicy = new AuthorizationPolicyBuilder()
.RequireAuthenticatedUser()
.Build();
builder.Services.AddAuthorizationBuilder()
.SetFallbackPolicy(requireAuthPolicy);
將新的 Logout.cshtml
和 SignedOut.cshtml
Razor 頁面新增至專案
必須登出以簽出 cookie 工作階段和 OpenID Connect 工作階段。 整個應用程式需要重新導向至 OpenID Connect 伺服器才能註銷。成功註銷之後,應用程式會開啟 RedirectUri
路由。
實作預設登出頁面,並將 Logout
Razor 頁面程式碼變更如下:
[Authorize]
public class LogoutModel : PageModel
{
public IActionResult OnGetAsync()
{
return SignOut(new AuthenticationProperties
{
RedirectUri = "/SignedOut"
},
// Clear auth cookie
CookieAuthenticationDefaults.AuthenticationScheme,
// Redirect to OIDC provider signout endpoint
OpenIdConnectDefaults.AuthenticationScheme);
}
}
SignedOut.cshtml
需要 [AllowAnonymous]
屬性:
[AllowAnonymous]
public class SignedOutModel : PageModel
{
public void OnGet()
{
}
}
實作 Login
頁面
也可以實作一個 Login
Razor 頁面,以所需的 AuthProperties
直接呼叫 ChallengeAsync
。 如果 Web 應用程式需要驗證,且使用預設挑戰,則不需要此專案。
Login.cshtml
頁面需要 [AllowAnonymous]
屬性:
using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.RazorPages;
namespace RazorPageOidc.Pages;
[AllowAnonymous]
public class LoginModel : PageModel
{
[BindProperty(SupportsGet = true)]
public string? ReturnUrl { get; set; }
public async Task OnGetAsync()
{
var properties = GetAuthProperties(ReturnUrl);
await HttpContext.ChallengeAsync(properties);
}
private static AuthenticationProperties GetAuthProperties(string? returnUrl)
{
const string pathBase = "/";
// Prevent open redirects.
if (string.IsNullOrEmpty(returnUrl))
{
returnUrl = pathBase;
}
else if (!Uri.IsWellFormedUriString(returnUrl, UriKind.Relative))
{
returnUrl = new Uri(returnUrl, UriKind.Absolute).PathAndQuery;
}
else if (returnUrl[0] != '/')
{
returnUrl = $"{pathBase}{returnUrl}";
}
return new AuthenticationProperties { RedirectUri = returnUrl };
}
}
為使用者新增登入和註銷按鈕
@if (Context.User.Identity!.IsAuthenticated)
{
<li class="nav-item">
<a class="nav-link text-dark" asp-area="" asp-page="/Logout">Logout</a>
</li>
<span class="nav-link text-dark">Hi @Context.User.Identity.Name</span>
}
else
{
<li class="nav-item">
<a class="nav-link text-dark" asp-area="" asp-page="/Index">Login</a>
</li>
}
代碼段的範例
使用使用者資訊端點的範例
OpenID Connect 選項可用來對應宣告、實作處理程式,或甚至將令牌儲存在會話中,以供稍後使用。
Scope
選項可用來請求不同的權利要求或刷新令牌,並將這些資訊傳送至 OpenID Connect 伺服器。 發出 offline_access
要求伺服器返回一個參考令牌,這個令牌可用來重新整理會話,而無需再次驗證應用程式的使用者。
services.AddAuthentication(options =>
{
options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
options.DefaultChallengeScheme = OpenIdConnectDefaults.AuthenticationScheme;
})
.AddCookie()
.AddOpenIdConnect(OpenIdConnectDefaults.AuthenticationScheme, options =>
{
var oidcConfig = builder.Configuration.GetSection("OpenIDConnectSettings");
options.Authority = oidcConfig["IdentityProviderUrl"];
options.ClientSecret = oidcConfig["ClientSecret"];
options.ClientId = oidcConfig["Audience"];
options.ResponseType = OpenIdConnectResponseType.Code;
options.Scope.Clear();
options.Scope.Add("openid");
options.Scope.Add("profile");
options.Scope.Add("email");
options.Scope.Add("offline_access");
options.ClaimActions.Remove("amr");
options.ClaimActions.MapUniqueJsonKey("website", "website");
options.GetClaimsFromUserInfoEndpoint = true;
options.SaveTokens = true;
// .NET 9 feature
options.PushedAuthorizationBehavior = PushedAuthorizationBehavior.Require;
options.TokenValidationParameters.NameClaimType = "name";
options.TokenValidationParameters.RoleClaimType = "role";
});
實作Microsoft識別提供者
Microsoft有多個識別提供者和 OpenID Connect 實作。 Microsoft有不同的 OpenID Connect 伺服器:
- Microsoft Entra ID
- Microsoft Entra 外部 ID (部分機器翻譯)
- Azure AD B2C
如果在 ASP.NET Core 中使用其中一個 Microsoft 身份識別提供者進行驗證,建議您使用 Microsoft.Identity.Web
NuGet 套件。
Microsoft.Identity.Web
Nuget 套件是 Microsoft 專用的用戶端,建置在 ASP.NET Core OpenID Connect 用戶端之上,並對預設用戶端進行了一些變更。
使用第三方 OpenID Connect 提供者用戶端
許多 OpenID Connect 伺服器實作都會建立針對相同 OpenID Connect 實作優化的 Nuget 套件。 這些套件會實作 OpenID Connect 客戶端細節,其中包含特定 OpenID Connect 伺服器所需的額外專案。
Microsoft.Identity.Web
是其中一個範例。
如果在單一應用程式中從不同的OpenID Connect 伺服器實作多個OpenID Connect用戶端,通常最好還原為預設的 ASP.NET Core實作,因為不同的用戶端會覆寫某些會影響其他客戶端的選項。
OpenIddict Web 提供者 是一種用戶端實作,可支援許多不同的伺服器實作。
IdentityModel
是用於宣告型身分識別、OAuth 2.0 和 OpenID Connect 的 .NET 標準輔助程式庫。 這也可以用來協助客戶端實作。
前端的後端 (BFF) 安全性架構
不建議再針對任何 Web 應用程式實作 OpenID Connect 公用用戶端。
如需詳細資訊,請參閱適用於 Browser-Based Applications的
如果要實作沒有獨立後端的 Web 應用程式,我們建議使用 前端後端 (BFF) 模式 安全架構。 此模式可以透過不同的方式實作,但驗證一律會在後端實作,而且不會傳送任何敏感數據給 Web 用戶端,以進行進一步的授權或驗證流程。
進階功能、標準、擴充 OIDC 用戶端
記錄
偵錯 OpenID Connect 用戶端可能很難。 根據預設,不會記錄個人標識資訊 (PII) 數據。 如果在開發模式中偵錯,則 IdentityModelEventSource.ShowPII
可以用來記錄敏感個人資料。 請勿將具有 IdentityModelEventSource.ShowPII
的應用程式部署到生產力伺服器。
//using ...
using Microsoft.IdentityModel.Logging;
var builder = WebApplication.CreateBuilder(args);
//... code
var app = builder.Build();
IdentityModelEventSource.ShowPII = true;
//... code
app.Run();
如需詳細資訊,請參閱 記錄。
注意
您可能想要降低設定的記錄層級,以查看所有必要的記錄。
OIDC 和 OAuth 參數自訂
OAuth 和 OIDC 驗證處理程式 (AdditionalAuthorizationParameters) 選項允許自訂通常包含在重新導向查詢字串中的授權訊息參數。
從 OpenID Connect 對應宣告
如需詳細資訊,請參閱 Core ASP.NET中的對應、自定義和轉換宣告。
Blazor OpenID Connect
如需詳細資訊,請參閱 使用 OpenID Connect 保護 ASP.NET Core Blazor Web App。