net mvc asp c# asp.net-mvc authentication claims-based-identity

c# - asp - Problema de token antifalsificación(MVC 5)



asp net identity claims (6)

Tengo un problema con el token anti falsificación :( Creé mi propia clase User que funcionaba bien, pero ahora recibo un error cada vez que voy a la página / Account / Register . El error es:

Se realizó un reclamo de tipo '' http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier '' o '' http://schemas.microsoft.com/accesscontrolservice/2010/07/claims/identityprovider '' no presente en el ClaimsIdentity proporcionado. Para habilitar el soporte de token antifalsificación con la autenticación basada en notificaciones, verifique que el proveedor de notificaciones configurado proporciona ambos reclamos en las instancias de ClaimsIdentity que genera. Si el proveedor de notificaciones configurado en su lugar utiliza un tipo de notificación diferente como identificador único, se puede configurar estableciendo la propiedad estática AntiForgeryConfig.UniqueClaimTypeIdentifier.

Encontré este artículo:

http://stack247.wordpress.com/2013/02/22/antiforgerytoken-a-claim-of-type-nameidentifier-or-identityprovider-was-not-present-on-provided-claimsidentity/

así que cambié mi método Application_Start a esto:

protected void Application_Start() { AreaRegistration.RegisterAllAreas(); FilterConfig.RegisterGlobalFilters(GlobalFilters.Filters); RouteConfig.RegisterRoutes(RouteTable.Routes); BundleConfig.RegisterBundles(BundleTable.Bundles); AntiForgeryConfig.UniqueClaimTypeIdentifier = ClaimTypes.Email; }

pero cuando hago eso, obtengo este error:

Un reclamo de tipo '' http://schemas.xmlsoap.org/ws/2005/05/identity/claims/emailaddress '' no estaba presente en el ClaimsIdentity proporcionado.

¿Alguien ha encontrado esto antes? Si es así, ¿sabes cómo resolverlo?

Saludos de antemano,
r3plica

Actualización 1

Aquí está mi clase de usuario personalizada:

public class Profile : User, IProfile { public Profile() : base() { this.LastLoginDate = DateTime.UtcNow; this.DateCreated = DateTime.UtcNow; } public Profile(string userName) : base(userName) { this.CreatedBy = this.Id; this.LastLoginDate = DateTime.UtcNow; this.DateCreated = DateTime.UtcNow; this.IsApproved = true; } [NotMapped] public HttpPostedFileBase File { get; set; } [Required] public string CompanyId { get; set; } [Required] public string CreatedBy { get; set; } public string ModifiedBy { get; set; } public DateTime DateCreated { get; set; } public DateTime? DateModified { get; set; } public DateTime LastLoginDate { get; set; } [Required(ErrorMessageResourceType = typeof(Resources.Resources), ErrorMessageResourceName = "RequiredTitle")] public string Title { get; set; } [Required(ErrorMessageResourceType = typeof(Resources.Resources), ErrorMessageResourceName = "RequiredFirstName")] public string Forename { get; set; } [Required(ErrorMessageResourceType = typeof(Resources.Resources), ErrorMessageResourceName = "RequiredLastName")] public string Surname { get; set; } [Required(ErrorMessageResourceType = typeof(Resources.Resources), ErrorMessageResourceName = "RequiredEmail")] public string Email { get; set; } public string JobTitle { get; set; } public string Telephone { get; set; } public string Mobile { get; set; } public string Photo { get; set; } public string LinkedIn { get; set; } public string Twitter { get; set; } public string Facebook { get; set; } public string Google { get; set; } public string Bio { get; set; } public string CompanyName { get; set; } [Required(ErrorMessageResourceType = typeof(Resources.Resources), ErrorMessageResourceName = "RequiredCredentialId")] public string CredentialId { get; set; } [Required(ErrorMessageResourceType = typeof(Resources.Resources), ErrorMessageResourceName = "RequiredSecurityCode")] public bool IsLockedOut { get; set; } public bool IsApproved { get; set; } [Display(Name = "Can only edit own assets")] public bool CanEditOwn { get; set; } [Display(Name = "Can edit assets")] public bool CanEdit { get; set; } [Display(Name = "Can download assets")] public bool CanDownload { get; set; } [Display(Name = "Require approval to upload assets")] public bool RequiresApproval { get; set; } [Display(Name = "Can approve assets")] public bool CanApprove { get; set; } [Display(Name = "Can synchronise assets")] public bool CanSync { get; set; } public bool AgreedTerms { get; set; } public bool Deleted { get; set; } } public class ProfileContext : IdentityStoreContext { public ProfileContext(DbContext db) : base(db) { this.Users = new UserStore<Profile>(this.DbContext); } } public class ProfileDbContext : IdentityDbContext<Profile, UserClaim, UserSecret, UserLogin, Role, UserRole> { }

El perfil es simple para mis repositorios, se ve así:

public interface IProfile { string Id { get; set; } string CompanyId { get; set; } string UserName { get; set; } string Email { get; set; } string CredentialId { get; set; } }

y la clase User es la clase Microsoft.AspNet.Identity.EntityFramework.User . Mi AccountController se ve así:

[Authorize] public class AccountController : Controller { public IdentityStoreManager IdentityStore { get; private set; } public IdentityAuthenticationManager AuthenticationManager { get; private set; } public AccountController() { this.IdentityStore = new IdentityStoreManager(new ProfileContext(new ProfileDbContext())); this.AuthenticationManager = new IdentityAuthenticationManager(this.IdentityStore); } // // GET: /Account/Register [AllowAnonymous] public ActionResult Register() { return View(); } // // POST: /Account/Register [HttpPost] [AllowAnonymous] public async Task<ActionResult> Register(RegisterViewModel model) { if (ModelState.IsValid) { try { // Create a profile, password, and link the local login before signing in the user var companyId = Guid.NewGuid().ToString(); var user = new Profile(model.UserName) { CompanyId = companyId, Title = model.Title, Forename = model.Forename, Surname = model.Surname, Email = model.Email, CompanyName = model.CompanyName, CredentialId = model.CredentialId }; if (await IdentityStore.CreateLocalUser(user, model.Password)) { //Create our company var company = new Skipstone.Web.Models.Company() { Id = companyId, CreatedBy = user.Id, ModifiedBy = user.Id, Name = model.CompanyName }; using (var service = new CompanyService()) { service.Save(company); } await AuthenticationManager.SignIn(HttpContext, user.Id, isPersistent: false); return RedirectToAction("Setup", new { id = companyId }); } else { ModelState.AddModelError("", "Failed to register user name: " + model.UserName); } } catch (IdentityException e) { ModelState.AddModelError("", e.Message); } } // If we got this far, something failed, redisplay form return View(model); } // // POST: /Account/Setup public ActionResult Setup(string id) { var userId = User.Identity.GetUserId(); using (var service = new CompanyService()) { var company = service.Get(id); var profile = new Profile() { Id = userId, CompanyId = id }; service.Setup(profile); return View(company); } } }

Solía ​​estar decorado con el atributo [ValidateAntiForgeryToken] , pero ahí es donde dejó de funcionar.

Espero que sea suficiente código :)


¿Sabe qué reclamos obtiene en su ClaimsIdentity? Si no:

  1. Eliminar el atributo [ValidateAntiForgeryToken]
  2. Ponga un punto de interrupción en algún lugar de su controlador y rompa en él
  3. Luego mire la ClaimsIdentity actual y examine los reclamos
  4. Encuentra uno que creas que identificará de manera única a tu usuario
  5. Establezca AntiForgeryConfig.UniqueClaimTypeIdentifier en ese tipo de reclamación

Editar: Teniendo una mayor comprensión de este problema en este momento, puedes ignorar mi respuesta a continuación.

Setting AntiForgeryConfig.UniqueClaimTypeIdentifier = ClaimTypes.NameIdentifier; en Application_Start () de Global.asax.cs lo arregló para mí. Aunque tengo el reclamo http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier set, obtengo el mismo error que en la pregunta original. Pero señalarlo como arriba funciona de alguna manera.

Comenzando con MVC4, el token anti falsificación no usa User.Identity.Name como el identificador único. En su lugar, busca las dos afirmaciones dadas en el mensaje de error.

Actualización NOTA: Esto no debería ser necesario . Puede agregar las reclamaciones faltantes a su ClaimsIdentity cuando el usuario está iniciando sesión, de esta manera:

string userId = TODO; var identity = System.Web.HttpContext.Current.User.Identity as ClaimsIdentity; identity.AddClaim(new Claim("http://schemas.microsoft.com/accesscontrolservice/2010/07/claims/identityprovider", userId)); identity.AddClaim(new Claim("http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier", userId));

Tenga en cuenta que uno de los reclamos ya puede estar allí desde antes, y obtendrá un error con reclamaciones duplicadas si agrega ambos. Si es así, solo agrega el que falta.


En Global.asax.cs,

1. Añadir estos espacios de nombres

using System.Web.Helpers; using System.Security.Claims;

2.Agregue esta línea en el método Application_Start:

protected void Application_Start() { ....... AntiForgeryConfig.UniqueClaimTypeIdentifier = ClaimsIdentity.DefaultNameClaimType; }


Intenta configurar (en global.cs):

AntiForgeryConfig.UniqueClaimTypeIdentifier = ClaimTypes.NameIdentifier;


Pruebe abrir el enlace en la ventana de incógnito o borrar la cookie de ese dominio (es decir, localhost).


Solo pon esto en global.asax.cs

AntiForgeryConfig.UniqueClaimTypeIdentifier = ClaimsIdentity.DefaultNameClaimType;