MVC5(VS2012)标识CreateIdentityAsync - 值不能为null

Jon*_*Jon 34 asp.net identity claims-based-identity asp.net-mvc-5 asp.net-identity

我正在尝试为MVC5站点设置OAuth(在VS2012中).

我正在使用Fluent NHibernate.我已经设置了自己的Userstore并传入一个存储库对象来访问NHibernate会话对象.我将我的商店传递给默认的aspnet usermanager提供程序.这最终适用于本地注册和登录.我不是要设置连接/注册Facebook.

它获得了一个成功的帐户.在用户表中添加用户,在登录表中添加记录然后爆炸.我没有在用户存储中实现声明,或者在用户对象中放置声明集合.(不确定这是否真的需要,我正在剥离所有可能出错的东西以找到问题的根源).

爆炸的线是(在账户控制器中):

var identity = await UserManager.CreateIdentityAsync(user, DefaultAuthenticationTypes.ApplicationCookie);            
Run Code Online (Sandbox Code Playgroud)

在这种方法中:

private async Task SignInAsync(IdentityUser user, bool isPersistent)
Run Code Online (Sandbox Code Playgroud)

这是堆栈跟踪的结束

[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.<CreateAsync>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.<SignInAsync>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.<ExternalLoginConfirmation>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<IdentityUserLogin>();
    }

    public string Id { get; set; }
    public string UserName { get; set; }
    public string PasswordHash { get; set; }
    public string SecurityStamp { get; set; }
    public IList<IdentityUserLogin> Logins { get; set; }

}

public class IdentityUserLogin
{
    public string LoginProvider { get; set; }
    public string ProviderKey { get; set; }
}
Run Code Online (Sandbox Code Playgroud)

如果需要,我可以包含我的用户代码:我没有把它放入,因为它是一个大文件,可能会减少问题.

我不确定为什么它甚至试图创建索赔对象以及为什么它会爆炸.因为我只有VS2012,所以我一直在网上的例子中修补它们.


正如@Shoe所建议我继承自UserManager:

public class NHibernateAspnetUserManager<TUser> : UserManager<TUser> where TUser : IdentityUser
{
    public NHibernateAspnetUserManager(IUserStore<TUser> store) : base(store)
    {
    }        

    public override Task<ClaimsIdentity> CreateIdentityAsync(TUser user, string authenticationType)
    {
        ClaimsIdentity identity = new ClaimsIdentity();
        return Task.FromResult(identity);
    }
}
Run Code Online (Sandbox Code Playgroud)

它现在不再抛出错误,但实际上并没有验证我多少次使用Facebook注册/登录.


总结一下.有了@ Shoe的信息,我试图重写UserManager.CreateIdentityAsync:

public override Task<ClaimsIdentity> CreateIdentityAsync(TUser user, string authenticationType)
    {
        var identity = new ClaimsIdentity();
        identity.AddClaim(new Claim(ClaimTypes.Name, user.UserName));
        return Task.FromResult(identity);
    }
Run Code Online (Sandbox Code Playgroud)

并尝试使用返回的默认值(空列表)实现IUserClaimStore.

第一个不会通过错误但不会最终验证.后者仍将通过奇怪的声明"System.Security.Claims.Claim..ctor"错误

编辑

找出ctor错误发生的原因.用户对象返回时没有ID,因此默认情况下UserManager感到不安.修复了并使用了UserManager现在不再抛出错误的默认值,但仍然没有记录用户.它返回的身份对象看起来很好.

Pat*_*ins 80

我在过去遇到了同样的错误,但只有在我使用Entity Framework Migration Tool创建用户时才会出错.在创建用户并使用网站签名时,我没有错误.

我的错误是我没有向SecurityStamp提供迁移.

SecurityStamp = Guid.NewGuid().ToString()
Run Code Online (Sandbox Code Playgroud)

这个属性设置,一切正常.


小智 13

我遇到了类似的问题.解决方案是设置User-Entity的SecurityStamp-Property.

背景:客户希望在数据库中拥有带密码的Admin-/Superuser-Accounts,以及一组其他用户 - 他们应该能够在没有密码的情况下登录 - 在XML文件中......

所以我从Entity Framework UserStore继承,覆盖FindByIdAsync和FindByNameAsync,为用户搜索XML文件并返回一个新的User-Entity.(如果默认实现没有找到用户)

在创建ClaimsIdentity时,我和Jon有相同的例外.

经过一番挖掘后,我发现我新创建的User-Entities没有SecurityStamp.而asp.net默认的UserManager需要一个SecurityStamp,并希望在ClaimsIdentity中将其设置为一个Claim.

在为该属性设置值后 - 我使用了包含前缀和用户名的字符串 - 一切都适合我.


AFe*_*ter 6

当密码少于 6 个字符时,我遇到了这个问题。任何比这更大的东西我都不会收到这个错误。

6 个字符是其最小默认设置。

当然你可以改变这种行为。

services.Configure<IdentityOptions>(options =>
                {
                    options.Password.RequiredLength = 6;
                    options.Password.RequireUppercase = false;
                    options.Password.RequireLowercase = false;
                    options.Password.RequireDigit = false;
                    options.Password.RequireNonAlphanumeric = false;
                });
Run Code Online (Sandbox Code Playgroud)


Sho*_*hoe 1

默认情况下,UserManager即使您尚未实现声明,也会尝试获取声明并添加/删除声明。如果您不需要声明,我找到的解决方案是UserManager在您的UserStore.

public Task AddClaimAsync(TUser user, Claim claim)
{
    return Task.FromResult<int>(0);
}

public Task<IList<Claim>> GetClaimsAsync(TUser user)
{
    return Task.FromResult<IList<Claim>>(new List<Claim>());
}

public Task RemoveClaimAsync(TUser user, Claim claim)
{
    return Task.FromResult<int>(0);
}
Run Code Online (Sandbox Code Playgroud)