问题
I am using asp.net identity 2 in a new mvc project (I've set it up to use an int user id instead of the default string identifier). It works successfully logging in normally with an existing account, but if I use the external sign in instead using the same email as the existing account, using Google sign in, I can sign in with Google, and allow the app, but when it redirects me to the ExternalLoginCallback action, it cannot find the user. GetExternalLoginInfoAsync() works to get the loginInfo, but when I pass that to ExternalSignIn, inside there, it cannot find the user when it calls var user = await UserManager.FindAsync(loginInfo.Login);. FindAsync returns null. Could this be a bug in the new identity framework? The user with this email address exists in the database already, so it should be able to find it (I have verified it's there too).
Here is the controller action (which is exactly the same as in the asp.net identity samples project):
public async Task<ActionResult> ExternalLoginCallback(string returnUrl)
{
var loginInfo = await AuthenticationManager.GetExternalLoginInfoAsync();
if (loginInfo == null)
{
return RedirectToAction("Login");
}
// Sign in the user with this external login provider if the user already has a login
var result = await SignInHelper.ExternalSignIn(loginInfo, isPersistent: false);
switch (result)
{
case SignInStatus.Success:
return RedirectToLocal(returnUrl);
case SignInStatus.LockedOut:
return View("Lockout");
case SignInStatus.RequiresTwoFactorAuthentication:
return RedirectToAction("SendCode", new { ReturnUrl = returnUrl });
case SignInStatus.Failure:
default:
// If the user does not have an account, then prompt the user to create an account
ViewBag.ReturnUrl = returnUrl;
ViewBag.LoginProvider = loginInfo.Login.LoginProvider;
return View("ExternalLoginConfirmation", new ExternalLoginConfirmationViewModel { Email = loginInfo.Email });
}
}
Here is the sign in method called in the above action (also what is in the identity samples project):
public async Task<SignInStatus> ExternalSignIn(ExternalLoginInfo loginInfo, bool isPersistent)
{
var user = await UserManager.FindAsync(loginInfo.Login);
if (user == null)
{
return SignInStatus.Failure;
}
if (await UserManager.IsLockedOutAsync(user.Id))
{
return SignInStatus.LockedOut;
}
return await SignInOrTwoFactor(user, isPersistent);
}
If I change FindAsync in the above method to FindByEmailAsync, it then finds the user - why not just find the user by email? i.e. var user = await UserManager.FindByEmailAsync(loginInfo.Email);
Just did some more research, and this seems to only happen when you change the pk to int and have to create a new custom user, role, etc class.
回答1:
You are trying to fetch data from the newly set identity object but the context is not updated yet.
There are two ways around this:
-Wait until the context is updated, by not accessing the User.identity infos yet, wait for next call.
-Try to get the context to save update.
var store = new UserStore<ApplicationUser>(new MyDbContext());
var manager = new UserManager(store);
manager.UpdateAsync(user);
var ctx = store.context;
ctx.saveChanges();
来源:https://stackoverflow.com/questions/24331293/asp-net-identity-2-external-sign-in-not-saving-userlogin-and-not-finding-user-af