将外部登录链接到现有用户

时间:2015-07-07 09:49:18

标签: asp.net-mvc asp.net-mvc-5 oauth-2.0 asp.net-identity-2

我对Identity很新,并试图通过观看https://channel9.msdn.com/Series/Customizing-ASPNET-Authentication-with-Identity中的视频来学习

在默认的ASP.Net MVC模板中,如果您已经登录,则可以将多个外部登录(google,facebook)链接到您的帐户(通过/Manage)。

但是,如果用户首次使用他们的Google帐户登录我们的网站并从该帐户退出并在另一天尝试使用他们的Facebook帐户登录,该怎么办?假设他们的facebook和Google帐户都使用相同的电子邮件地址,则用户将无法登录该网站,因为默认模板不允许,因为UserManager.CreateAsync将失败。我知道他们可以更改他们的电子邮件和登录信息,但这会为同一个用户创建两个不同的帐户。

var info = await AuthenticationManager.GetExternalLoginInfoAsync();
if (info == null)
{
    return View("ExternalLoginFailure");
}
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)
    {
        await SignInManager.SignInAsync(user, isPersistent: false, rememberBrowser: false);
        return RedirectToLocal(returnUrl);
    }
}

我更改了ExternalLoginConfirmation中的代码,以便检查用户是否存在并将新的外部提供商广告到AspNetUserLogins。任何人都可以告诉我,如果这是正确的方法吗?或者如果有更好的方法。

if (ModelState.IsValid)
        {
            // Get the information about the user from the external login provider
            var info = await AuthenticationManager.GetExternalLoginInfoAsync();
            if (info == null)
            {
                return View("ExternalLoginFailure");
            }
            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)
                {
                    await SignInManager.SignInAsync(user, isPersistent: false, rememberBrowser: false);
                    return RedirectToLocal(returnUrl);
                }
            }
            //new code begins
            else if (UserManager.FindByEmail(model.Email) != null)
            {
                var usr = await UserManager.FindByEmailAsync(model.Email);
                result = await UserManager.AddLoginAsync(usr.Id, info.Login);

                if (result.Succeeded)
                {
                    await SignInManager.SignInAsync(usr, isPersistent: false, rememberBrowser: false);
                    return RedirectToLocal(returnUrl);
                }
            }
            //new code ends
            AddErrors(result);
        }

1 个答案:

答案 0 :(得分:0)

我也很熟悉身份并遇到同样的问题,尽管我的解决方案完全不同。我不使用Entity Framework并实现这一点,我必须基本上用自定义类重写整个Identity引擎。我有自己的Sql Server表,它们与EF创建的表不同。 EF将身份存储在5个表中:用户,角色,用户角色,用户声明和用户登录。我只使用前三个。在我的环境中,不需要AddLoginAsync,因为该表不存在。我将所有本地/外部登录和注册用户存储在用户表中。声明在需要时存储为用户角色。

我绕过重复的UserNames和电子邮件(使用具有相同注册电子邮件地址的不同提供商登录)的方法是在创建用户之前使用自定义UserValidator删除现有用户名和电子邮件的验证检查。该表允许重复。登录时,我会根据用户名/提供商(外部)或电子邮件/密码哈希(本地)自定检查唯一性。它似乎正在发挥作用。