在ASP.NET Core中处理OpenID Connect错误事件
ASP.NET Core为处理OpenID Connect错误事件提供了出色的扩展点。本文探讨了在使用ASP.NET Core Identity实现的ASP.NET Core应用程序中实施错误处理的方法。
代码:https://github.com/damienbod/IdentityExternalErrorHandling
设置
应用程序使用OpenID Connect来实现用户身份认证。这实现了标准的OpenID Connect流程,并使用Microsoft Entra ID作为身份提供程序。应用程序还使用了ASP.NET Core Identity,可用于实现用户管理。这不是必需的,我通常在业务应用程序中避免使用它,因为在大多数情况下,这种逻辑可以委托给身份提供程序。
可以使用默认的ASP.NET Core OpenID Connect处理程序来实现任何OpenID Connect实现的逻辑。几乎所有产品和服务都为特定客户端提供客户端实现,并且所有这些都是默认ASP.NET Core接口的包装器。Microsoft为Microsoft Entra产品提供了Microsoft.Identity.Web Nuget包。只要您不在同一应用程序中使用任何其他OAuth或OpenID连接服务,这种方法就能很好地工作。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
// Identity.External
builder.Services.AddAuthentication(options =>
{
options.DefaultAuthenticateScheme = IdentityConstants.ApplicationScheme;
options.DefaultChallengeScheme = IdentityConstants.ApplicationScheme;
options.DefaultSignInScheme = IdentityConstants.ExternalScheme;
}).AddOpenIdConnect("EntraID", "EntraID", oidcOptions =>
{
oidcOptions.SignInScheme = IdentityConstants.ExternalScheme;
oidcOptions.SignOutScheme = IdentityConstants.ApplicationScheme;
oidcOptions.RemoteSignOutPath = new PathString("/signout-callback-oidc-entra");
oidcOptions.SignedOutCallbackPath = new PathString("/signout-oidc-entra");
oidcOptions.CallbackPath = new PathString("/signin-oidc-entra");
oidcOptions.Scope.Add("user.read");
oidcOptions.Authority = $"https://login.microsoftonline.com/{builder.Configuration["AzureAd:TenantId"]}/v2.0/";
oidcOptions.ClientId = builder.Configuration["AzureAd:ClientId"];
oidcOptions.ClientSecret = builder.Configuration["AzureAd:ClientSecret"];
oidcOptions.ResponseType = OpenIdConnectResponseType.Code;
oidcOptions.UsePkce = true;
oidcOptions.MapInboundClaims = false;
oidcOptions.SaveTokens = true;
oidcOptions.TokenValidationParameters.NameClaimType = JwtRegisteredClaimNames.Name;
oidcOptions.TokenValidationParameters.RoleClaimType = "role";
});
|
OpenID Connect事件
在OpenID Connect流程中实现自定义逻辑时,ASP.NET Core实现提供了许多事件。所有这些事件都可以用于特定需求。当实现从身份提供程序返回的错误逻辑时,没有一个事件可以用于此逻辑,因为每个产品或服务对此的实现和支持方式都不同。例如,一些提供程序不返回用户认证错误,而其他提供程序则返回。
1
2
3
4
5
6
7
8
9
10
11
12
|
oidcOptions.Events = new OpenIdConnectEvents
{
// 添加事件处理程序
OnTicketReceived = async context => {},
OnRedirectToIdentityProvider = async context => {},
OnPushAuthorization = async context => {},
OnMessageReceived = async context => {},
OnAccessDenied = async context => {},
OnAuthenticationFailed = async context => {},
OnRemoteFailure = async context => {},
// ...
};
|
处理远程错误
OnRemoteFailure可用于处理流程错误,例如请求中的密钥不正确。HandleResponse可用于防止错误事件的进一步处理,并且用户可以被重定向到用户友好的UI视图。
1
2
3
4
5
6
7
8
9
10
11
12
13
|
OnRemoteFailure = async context =>
{
var logger = context.HttpContext.RequestServices.GetRequiredService<ILogger<Program>>();
logger.LogInformation("OnRemoteFailure from identity provider. Scheme: {Scheme: }", context.Scheme.Name);
if (context.Failure != null)
{
context.HandleResponse();
context.Response.Redirect($"/Error?remoteError={context.Failure.Message}");
}
await Task.CompletedTask;
}
|
UI错误页面
可以使用Razor Page来显示错误。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
public class ErrorModel : PageModel
{
public string? RequestId { get; set; }
public string? Error { get; set; }
public string? ErrorDescription { get; set; }
public bool ShowRequestId => !string.IsNullOrEmpty(RequestId);
public void OnGet(string? remoteError)
{
if (remoteError != null)
{
Error = "Remote authentication error";
ErrorDescription = remoteError;
}
RequestId = Activity.Current?.Id ?? HttpContext.TraceIdentifier;
}
}
|
注意事项
用于实现OpenID Connect的ASP.NET Core API非常出色。所有实现OpenID Connect服务器的产品和服务都以不同的方式处理错误处理。根据软件中使用的身份产品,需要不同的事件来处理这种情况。
链接