MVC5 (VS2012) Identity CreateIdentityAsync – Il valore non può essere nullo

Sto cercando di configurare OAuth per un sito MVC5 (in VS2012).

Sto usando Fluent NHibernate. Ho configurato il mio Userstore e passaggio in un object repository per accedere all’object sessione NHibernate. Passo il mio negozio al provider di Usermanager di Aspnet predefinito. Questo alla fine ha funzionato per la registrazione locale e l’accesso. Non sto provando a configurare la connessione / registrazione con Facebook.

Ottiene un account di successo Aggiunge un utente nella tabella utente, aggiunge un record nella tabella dei login e quindi esplode. Non ho implementato le attestazioni nell’archivio utente o inserito una raccolta di attestazioni nell’object utente. (Non sono sicuro che sia effettivamente necessario, stavo spogliando tutto ciò che potrebbe essere sbagliato per trovare la fonte del problema).

La riga che esplode è, (nel controller account):

var identity = await UserManager.CreateIdentityAsync(user, DefaultAuthenticationTypes.ApplicationCookie); 

all’interno di questo metodo:

 private async Task SignInAsync(IdentityUser user, bool isPersistent) 

questa è la fine della traccia dello stack

 [ArgumentNullException: Value cannot be null. Parameter name: value] System.Security.Claims.Claim..ctor(String type, String value, String valueType, String issuer, String originalIssuer, ClaimsIdentity subject, String propertyKey, String propertyValue) +14108789 System.Security.Claims.Claim..ctor(String type, String value, String valueType) +62 Microsoft.AspNet.Identity.d__0.MoveNext() +481 System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) +144 System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) +84 System.Runtime.CompilerServices.TaskAwaiter`1.GetResult() +49 Web.Controllers.d__42.MoveNext() in d:\Google Drive\Development\GoalManagement\Web\Controllers\AccountController.cs:375 System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) +144 System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) +84 Web.Controllers.d__35.MoveNext() in d:\Google Drive\Development\GoalManagement\Web\Controllers\AccountController.cs:311 System.Runtime.CompilerServices.TaskAwaiter.ThrowForNonSuccess(Task task) +144 System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task) +84 public class IdentityUser : IUser { public IdentityUser() { Logins = new List(); } public string Id { get; set; } public string UserName { get; set; } public string PasswordHash { get; set; } public string SecurityStamp { get; set; } public IList Logins { get; set; } } public class IdentityUserLogin { public string LoginProvider { get; set; } public string ProviderKey { get; set; } } 

Posso includere il mio codice usertore se desiderato: non l’ho inserito perché è un file di grandi dimensioni e potrebbe sminuire il problema.

Non sono sicuro del motivo per cui sta anche tentando di creare l’object claim e perché sta esplodendo. Poiché ho solo VS2012, ho applicato il patching di tutti gli esempi principalmente online.


Come suggerito da @Shoe I ereditato da UserManager :

 public class NHibernateAspnetUserManager : UserManager where TUser : IdentityUser { public NHibernateAspnetUserManager(IUserStore store) : base(store) { } public override Task CreateIdentityAsync(TUser user, string authenticationType) { ClaimsIdentity identity = new ClaimsIdentity(); return Task.FromResult(identity); } } 

Ora non genera più un errore ma in realtà non mi autentica mai più spesso utilizzo il registro / login di Facebook.


Riassumere. Con le informazioni di @ Shoe ho provato a sovrascrivere UserManager.CreateIdentityAsync con:

 public override Task CreateIdentityAsync(TUser user, string authenticationType) { var identity = new ClaimsIdentity(); identity.AddClaim(new Claim(ClaimTypes.Name, user.UserName)); return Task.FromResult(identity); } 

e anche cercando di implementare IUserClaimStore con il valore predefinito di ritorno (lista vuota).

Il primo non passa attraverso un errore ma non finisce con l’autenticazione. Più tardi verrà ancora attraverso l’errore dispari “System.Security.Claims.Claim..ctor” errore

MODIFICARE

Scopri perché si è verificato l’errore del ctor. L’object utente tornava senza l’ID, quindi l’ UserManager predefinito UserManager stava UserManager . Risolto il UserManager e utilizzato l’ UserManager predefinito che ora non genera più un errore, ma continua a non registrare l’utente. L’object id quadro restituito sembra buono da quello che posso dire.

Ho avuto lo stesso errore in passato, ma solo quando ho creato l’utente con Entity Framework Migration Tool. Durante la creazione di un utente e la firma con il sito Web, non ho avuto errori.

Il mio errore era che non stavo fornendo un SecurityStamp con la migrazione.

 SecurityStamp = Guid.NewGuid().ToString() 

Questo set di proprietà, tutto ha funzionato.

Ho avuto un problema simile. La soluzione era di impostare la proprietà SecurityStamp dell’entity framework utente.

Background: il cliente desidera avere account Admin / Superuser con password nel database e un gruppo di utenti aggiuntivi – che devono essere in grado di accedere senza password – in un file XML …

Pertanto, eredito da Entity Framework UserStore, sostituisco FindByIdAsync e FindByNameAsync, eseguo la ricerca nel file XML per l’utente e restituisco una nuova Entità utente. (se nessun utente è stato trovato dall’implementazione predefinita)

Ho avuto la stessa eccezione di Jon durante la creazione di ClaimsIdentity.

Dopo alcuni scavi ho scoperto che le mie Entità Utente appena create non avevano un SecurityStamp. E l’UserManager predefinito asp.net si aspetta un SecurityStamp e vuole impostarlo come Claim in ClaimsIdentity.

Dopo aver impostato un valore su quella proprietà, ho usato una stringa che contiene un prefisso e il nome utente: tutto funziona correttamente per me.

Ho fatto la stessa cosa di @ user3347549.

Mi ci è voluto un po ‘per capire da dove proviene davvero l’errore, complimenti per dotPeek!

Sto usando la mia implementazione di UserManager e UserStore, perché volevo i tipi di guida (uniqueidentifier in MSSQL) come chiavi e non stringa (anche se sono solo segnaposto per Guids)

Grazie a questo link e in particolare questa risposta, che ho incluso come riferimento nel caso in cui il link sparisse, da HaoK (@Hao Kung qui su SO):

Dovresti seminare il timbro di sicurezza con qualcosa di casuale, come un nuovo lavoro di guida.

Ho implementato il mio ClaimsIdentityFactory (che sembra esattamente lo stesso da quello che ho raccolto in dotPeek) e ho appena modificato una riga nel metodo CreateAsync

 public class ClaimsIdentityFactory : IClaimsIdentityFactory where TUser : class, IUser where TKey : IEquatable { ///  /// Claim type used for role claims ///  public string RoleClaimType { get; set; } ///  /// Claim type used for the user name ///  public string UserNameClaimType { get; set; } ///  /// Claim type used for the user id ///  public string UserIdClaimType { get; set; } ///  /// Claim type used for the user security stamp ///  public string SecurityStampClaimType { get; set; } ///  /// Constructor ///  public ClaimsIdentityFactory() { RoleClaimType = "http://schemas.microsoft.com/ws/2008/06/identity/claims/role"; UserIdClaimType = "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/nameidentifier"; UserNameClaimType = "http://schemas.xmlsoap.org/ws/2005/05/identity/claims/name"; SecurityStampClaimType = "AspNet.Identity.SecurityStamp"; } ///  /// Create a ClaimsIdentity from a user ///  ///  ///  ///  ///  ///  ///  ///  ///  public virtual async Task CreateAsync(UserManager manager, TUser user, string authenticationType) { if (manager == null) throw new ArgumentNullException("manager"); if (user == null) throw new ArgumentNullException("user"); var id = new ClaimsIdentity(authenticationType, UserNameClaimType, RoleClaimType); id.AddClaim(new Claim(UserIdClaimType, ConvertIdToString(user.Id), "http://www.w3.org/2001/XMLSchema#string")); id.AddClaim(new Claim(UserNameClaimType, user.UserName, "http://www.w3.org/2001/XMLSchema#string")); id.AddClaim(new Claim("http://schemas.microsoft.com/accesscontrolservice/2010/07/claims/identityprovider", "ASP.NET Identity", "http://www.w3.org/2001/XMLSchema#string")); if (manager.SupportsUserSecurityStamp) { ClaimsIdentity claimsIdentity1 = id; string securityStampClaimType = SecurityStampClaimType; ClaimsIdentity claimsIdentity2 = claimsIdentity1; string str = await manager.GetSecurityStampAsync(user.Id).ConfigureAwait(false); Claim claim = new Claim(securityStampClaimType, str ?? Guid.NewGuid().ToString()); claimsIdentity2.AddClaim(claim); } if (manager.SupportsUserRole) { IList roles = await manager.GetRolesAsync(user.Id).ConfigureAwait(false); foreach (string str in roles) id.AddClaim(new Claim(RoleClaimType, str, "http://www.w3.org/2001/XMLSchema#string")); } if (manager.SupportsUserClaim) id.AddClaims(await manager.GetClaimsAsync(user.Id).ConfigureAwait(false)); return id; } ///  /// Convert the key to a string, by default just calls .ToString() ///  ///  ///  ///  ///  protected virtual string ConvertIdToString(TKey key) { if ((object)key == null) throw new ArgumentNullException("key"); else return key.ToString(); } } 

La linea che ho modificato era da

 Claim claim = new Claim(securityStampClaimType, str); 

a

 Claim claim = new Claim(securityStampClaimType, str ?? Guid.NewGuid().ToString()); 

Devo ancora capire cosa significa, ma almeno funziona per ora e posso continuare a testare la mia applicazione. Presumo che questo errore venga visualizzato perché non ho completamente implementato alcuna parte dello stack Identity. Per utilizzare questo nuovo factory, digita questo nel costruttore UserManager:

 ClaimsIdentityFactory = new ClaimsIdentityFactory(); 

UserManager predefinito tenterà di ottenere le attestazioni e aggiungere / rimuovere attestazioni anche se non sono state implementate. Se non hai bisogno di reclami, la soluzione che ho trovato è quella di implementare il tuo UserManager o implementare metodi “non fare nulla” nel tuo UserStore .

 public Task AddClaimAsync(TUser user, Claim claim) { return Task.FromResult(0); } public Task> GetClaimsAsync(TUser user) { return Task.FromResult>(new List()); } public Task RemoveClaimAsync(TUser user, Claim claim) { return Task.FromResult(0); } 

Ho dovuto implementare ClaimsIdentityFactory e impostare la proprietà UserManager.ClaimsIdentityFactory ovvero nella class AccountController.

Nel mio caso era qualcosa di completamente diverso. Era una questione di ordinamento del codice di avvio di Owin

Il mio codice bacato:

 public void ConfigureAuth(IAppBuilder app) { //... app.CreatePerOwinContext(ApplicationDbContext.Create); app.CreatePerOwinContext(AppUserManager.Create); app.CreatePerOwinContext(AppSignInManager.Create); app.CreatePerOwinContext(AppRoleManager.Create); //... } 

AppSignInManager stava cercando di AppUserManager che è sempre null perché non è stato ancora aggiunto a Owin.

Semplicemente scambiandoli insieme, tutto ha funzionato come un incantesimo

 public void ConfigureAuth(IAppBuilder app) { //... app.CreatePerOwinContext(ApplicationDbContext.Create); app.CreatePerOwinContext(AppSignInManager.Create); app.CreatePerOwinContext(AppUserManager.Create); app.CreatePerOwinContext(AppRoleManager.Create); //... }