ASP.NET MVC5项目Owin认证管道中Custom ClaimsIdentity技术咨询
Hey Luca! Let's dive into your Custom ClaimsIdentity questions related to your ASP.NET MVC5 OWIN auth setup. First, let's break down what you already have configured, then cover common scenarios and solutions you might be looking for.
Looking at your Startup class, here's what each piece is doing:
CustomTicketSerializer<CustomClaimsIdentity>: You’re replacing the default auth ticket serializer to handle your custom identity type. This is crucial because the out-of-the-box serializer doesn’t know how to handle any extra properties you’ve added toCustomClaimsIdentity—without this, your custom data would get lost when the auth ticket is serialized to the cookie.- Default Sign-In Type: Setting
CookieAuthenticationDefaults.AuthenticationTypeas the default means after successful OpenID Connect authentication, the user’s identity will be persisted in a cookie for subsequent requests. - OpenID Connect Middleware: This handles the full OAuth2/OpenID flow with your identity provider, validates incoming tokens, and creates an initial identity that you can extend with your custom claims.
Here are the most frequent questions and solutions for working with a custom ClaimsIdentity in this setup:
1. Adding Custom Claims After Authentication
If you need to inject app-specific claims (like roles from your database, user metadata, or subscription status) after the OpenID Connect token is validated, hook into the SecurityTokenValidated notification in your OpenIdConnectAuthenticationOptions:
app.UseOpenIdConnectAuthentication( new OpenIdConnectAuthenticationOptions { ClientId = "xxx", ClientSecret = "xxx", // ... other required settings (Authority, RedirectUri, etc.) Notifications = new OpenIdConnectAuthenticationNotifications { SecurityTokenValidated = async n => { // Grab the initial identity from the validated token var baseIdentity = n.AuthenticationTicket.Identity as ClaimsIdentity; // Initialize your custom identity (extend the base one) var customIdentity = new CustomClaimsIdentity(baseIdentity); // Add your custom claims here customIdentity.AddClaim(new Claim("app:subscription_level", "premium")); customIdentity.AddClaim(new Claim(ClaimTypes.Role, "ContentManager")); // Replace the ticket's identity with your custom one n.AuthenticationTicket = new AuthenticationTicket( customIdentity, n.AuthenticationTicket.Properties ); } } } );
This ensures your custom claims are added before the auth cookie is written, so they’ll be available on every subsequent request.
2. Implementing the Custom Ticket Serializer Correctly
Your CustomTicketSerializer<CustomClaimsIdentity> needs to handle both serialization and deserialization of any custom properties on your identity. Here’s a template to follow:
public class CustomTicketSerializer<T> : TicketSerializer where T : ClaimsIdentity { protected override void WriteIdentity(BinaryWriter writer, ClaimsIdentity identity) { if (identity is not T customIdentity) { // Fall back to base serializer if it's not our custom identity base.WriteIdentity(writer, identity); return; } // First serialize the base ClaimsIdentity properties base.WriteIdentity(writer, customIdentity); // Now serialize your custom properties (example: a UserId property) writer.Write(customIdentity.UserId); // Adjust based on your property type } protected override ClaimsIdentity ReadIdentity(BinaryReader reader) { // Read the base identity first var baseIdentity = base.ReadIdentity(reader) as T; if (baseIdentity == null) return baseIdentity; // Read back your custom properties in the same order you wrote them baseIdentity.UserId = reader.ReadString(); return baseIdentity; } }
⚠️ Pro Tip: If you’re storing complex objects in your custom identity, serialize them to a JSON string first before writing to the BinaryWriter—this avoids serialization errors.
3. Accessing the Custom Identity in Controllers
Once your custom identity is set up, you can access it in your MVC controllers by casting User.Identity to your CustomClaimsIdentity type:
public ActionResult UserDashboard() { var customIdentity = User.Identity as CustomClaimsIdentity; if (customIdentity != null) { var userId = customIdentity.UserId; var subscriptionLevel = customIdentity.FindFirst("app:subscription_level")?.Value; // Use these values to populate your view } return View(); }
To make this cleaner, create an extension method:
public static class IdentityExtensions { public static CustomClaimsIdentity AsCustomIdentity(this IIdentity identity) { return identity as CustomClaimsIdentity ?? throw new InvalidOperationException("Current user identity is not a CustomClaimsIdentity"); } }
Then use it like this:
var customIdentity = User.Identity.AsCustomIdentity(); var userId = customIdentity.UserId;
4. Properly Handling Sign-Out
When logging out, make sure you sign out of both the cookie authentication and OpenID Connect middleware to clear the session and revoke the identity provider token:
public ActionResult Logout() { HttpContext.GetOwinContext().Authentication.SignOut( CookieAuthenticationDefaults.AuthenticationType, OpenIdConnectAuthenticationDefaults.AuthenticationType ); return RedirectToAction("Index", "Home"); }
This ensures the custom identity cookie is deleted and the user is fully signed out of your app and the identity provider.
- Serialization Errors: If you get deserialization exceptions, double-check that you’re reading custom properties in the exact same order you wrote them in the serializer.
- Claims Not Showing Up: Ensure you’re replacing the
AuthenticationTicket’s identity in theSecurityTokenValidatedevent—modifying the identity without updating the ticket won’t persist changes to the cookie. - Casting Failures: If
User.Identitywon’t cast toCustomClaimsIdentity, verify your serializer is returning an instance ofCustomClaimsIdentityin theReadIdentitymethod.
内容的提问来源于stack exchange,提问作者Luca

