ASP.NET Core MVC如何将IdSrv自定义Claim映射到ApplicationUser属性
Great question! Let's break this down step by step since you're dealing with external OIDC authentication where the regular Identity SignInManager doesn't come into play.
When using OpenID Connect authentication in ASP.NET Core, the ClaimsPrincipal is constructed by the OpenIdConnect middleware during its authentication flow. Specifically:
- After validating the id_token received from IdentityServer, or after fetching user info from the UserInfo endpoint (since you have
GetClaimsFromUserInfoEndpoint = true), the middleware uses configuredTokenValidationParametersand a defaultClaimsPrincipalFactoryto build the principal. - You can intercept and modify this process using OIDC events, which is where we'll hook in to expose your
AvatarUrlas a direct property.
The default ClaimsIdentity (which User.Identity defaults to) doesn't have an AvatarUrl property, so we'll create a custom identity class and replace the default one during the OIDC flow. Here's how:
Step 1: Create a Custom ClaimsIdentity
Define a custom identity that inherits from ClaimsIdentity and pulls the AvatarUrl value from your mapped claim:
public class AppIdentity : ClaimsIdentity { public string AvatarUrl { get; } public AppIdentity(IEnumerable<Claim> claims, string authenticationType) : base(claims, authenticationType) { // Extract the avatarUrl claim value when initializing the identity AvatarUrl = claims.FirstOrDefault(c => c.Type == "avatarUrl")?.Value; } // Match other ClaimsIdentity constructor overloads if needed public AppIdentity(string authenticationType) : base(authenticationType) { } }
Step 2: Replace the Default Identity in the OIDC Flow
Modify your OpenIdConnect configuration to hook into the OnTokenValidated event—this fires after token validation and initial principal creation, letting you swap in your custom identity:
.AddOpenIdConnect("oidc", options => { // ... your existing configuration ... options.Events.OnTokenValidated = context => { // Create our custom identity using the existing claims and auth type var customIdentity = new AppIdentity(context.Principal.Claims, context.Principal.Identity.AuthenticationType); // Replace the default principal with one using our custom identity context.Principal = new ClaimsPrincipal(customIdentity); return Task.CompletedTask; }; // ... rest of your OIDC setup ... });
Step 3: Access AvatarUrl in Controllers
Now you can cast User.Identity to your custom AppIdentity to access the property directly:
public IActionResult Profile() { var appIdentity = HttpContext.User.Identity as AppIdentity; var avatarUrl = appIdentity?.AvatarUrl; // Use avatarUrl in your view or logic return View(); }
Optional: Add an Extension Method for Cleaner Access
To avoid casting everywhere, add an extension method for easier access:
public static class IdentityExtensions { public static string GetAvatarUrl(this IIdentity identity) { return (identity as AppIdentity)?.AvatarUrl ?? (identity as ClaimsIdentity)?.FindFirstValue("avatarUrl"); } }
Then use it like this:
var avatarUrl = HttpContext.User.Identity.GetAvatarUrl();
As you noticed, SignInManager is part of ASP.NET Core Identity's local authentication flow. When using external OIDC authentication, the OpenIdConnect middleware handles the entire process—validating tokens, fetching user info, creating the ClaimsPrincipal, and writing it to the cookie—without involving SignInManager at all. That's why your earlier attempt had no effect.
内容的提问来源于stack exchange,提问作者Etchelon

