我在通过 ASP.NET 身份添加外部登录的默认代码中遇到了问题。
我的帐户控制器外部登录确认方法中有以下代码:
var user = new ApplicationUser { UserName = model.Email, Email = model.Email };
var result = await UserManager.CreateAsync(user);
if (result.Succeeded)
{
result = await UserManager.AddLoginAsync(user.Id, info.Login);
if (result.Succeeded)
{
//do stuff
}
}
创建异步调用返回结果。成功==真。 但是,当它流经 AddLoginAsync 方法时,该方法将返回结果。成功==假,出现以下错误:
Name foo@bar.com is already taken.
Email 'foo@bar.com' is already taken.
当我查看 aspnetusers 表时,我看到此用户的新行,如预期的那样来自 CreateUserAsync 方法。 如果AddLoginAsync应该向现有用户添加登录名,为什么它会抛出错误,就像它期望用户不存在一样? 如果不事先在新用户实例中填充用户名和电子邮件,则无法调用 CreateAsync。
现成的标识设置之间的唯一区别是我创建了一个客户 ApplicationUser 类,该类使用 int 作为 Id 而不是字符串。
有什么想法吗?
错误消息是一条红鲱鱼。 尽管这是 MS 在创建新的 Web 应用程序时提供的默认代码,但CreateAsync
调用不会更新user
对象,因为它会引导您相信。 在本例中,用户。当 Id 传递到AddLoginAsync
时,它仍然等于 0,因此,当您的用户已创建时,您没有该对象的当前实例。
改变
var user = new ApplicationUser { UserName = model.Email, Email = model.Email };
var result = await UserManager.CreateAsync(user);
if (result.Succeeded)
{
//do stuff
}
自
var newuser = new ApplicationUser { UserName = model.Email, Email = model.Email };
var result = await UserManager.CreateAsync(newuser);
if (result.Succeeded)
{
var user = await UserManager.FindByEmailAsync(model.Email);
//do stuff
}
修复了问题。
检查 AspNetUserLogins 表。 特别是 AspNetUserLogins.UserId 列,以查看那里是否已经有一个条目。
UserManager.CreateAsync 在 AspNetUsers 表中创建一个条目。 UserManager.AddLoginAsync 在 AspNetUserLogins 中创建一个条目(按提供程序、提供程序密钥和 UserID 进行外部登录映射(。
AspNetUserLogins.UserId = AspNetUsers.Id
编辑:我进一步查看了这个.
您已经有一个帐户正在使用AspNetUsers表中的Email(Azure AD v1(/Name(Azure AD v1(/preferred_username(Azure AD v2(地址,因此ExternalLoginCallback中的调用正在设置SignInStatus.Fail,当调用SignInManager.ExternalSignInAsync(loginInfo,isPersistent:false(时。
潜在原因:
- 有人通过本地标识 2.0 注册使用该电子邮件地址,并且 AspNetUserLogins 中没有条目。检查 AspNetUsers.PasswordHash 对于该用户是否为空。 如果为 null,则它来自外部登录。 如果不是电子邮件地址是使用密码在本地注册的(外部登录仅通过不包含密码的JWT(。
- 有人在其他提供程序上使用了该电子邮件(方案你已注册开发、测试、生产 Azure AD 应用程序...TenantId 保持不变,但 ClientId(web.config name(/ApplicationId(Azure manifest name?(不同。 这将导致 AspNetUserLogins.ProviderKey 不匹配。 您必须调用UserManager.RemoveLogin,然后在ExternalLoginConfirmation中执行AddLogin。
您是否使用外部登录提供程序?如果不是,则不应调用AddLoginAsync((。
CreateAsync(user( 正在您的本地环境中为您创建用户记录。 之后,您可以选择使用 SignInAsync(( 登录用户,但我认为您不需要调用 AddLoginAsync((。