1

I have an MVC 5 site running identity with external logins. I've only slightly modified it to have f/l name and username separate from email.

I am not registering a new user, I am simply logging in via Fackbook... (this might be the issue?) If I login via Facebook, it creates a user in the identity tables (but no password hash is created).

However, when I nav to the 'Manage' controller, It's showing

External Logins: 0 [ Manage ]

And when I click 'manage', it takes me to 'Manage/ManageLogins' and shows a Facebook button... but upon clicking the FB button, I get 'an error has occurred'

Looking into the Manage Controller, I see this method getting hit, and where it gathers the userLogins, it isn't getting any.

 // GET: /Manage/ManageLogins
    public async Task<ActionResult> ManageLogins(ManageMessageId? message)
    {
        ViewBag.StatusMessage =
            message == ManageMessageId.RemoveLoginSuccess ? "The external login was removed."
            : message == ManageMessageId.Error ? "An error has occurred."
            : "";
        var user = await UserManager.FindByIdAsync(User.Identity.GetUserId());
        if (user == null)
        {
            return View("Error");
        }
    --> var userLogins = await UserManager.GetLoginsAsync(User.Identity.GetUserId()); <-- here it doesn't get any
        var otherLogins = AuthenticationManager.GetExternalAuthenticationTypes().Where(auth => userLogins.All(ul => auth.AuthenticationType != ul.LoginProvider)).ToList();
        ViewBag.ShowRemoveButton = user.PasswordHash != null || userLogins.Count > 1;
        return View(new ManageLoginsViewModel
        {
            CurrentLogins = userLogins,
            OtherLogins = otherLogins
        });
    }

NOTE: UserManager.GetLoginsAsync is always returning 0 and I've verified User.Identity.GetUserId() IS returning the user's id... it's just not getting the user. I just tried this with a freshly created local user.

This code only shows the 'remove' button if there is an existing userLogin... but there is no userLogin created when logging in via external login. Is this normal? I was expecting a userLogin to be created and referenced to the external, but I'm not sure how identity handles that aspect...

How do I work this out so that my users can still disassociate their FB account? Or is there no real account to disassociate from since it's an external login and never really registered as a local account?... Is that what I'm missing? Is this expected behaviour?

PS: I had to add a line of code to kill any existing sessions before the ChallengeResult call in the ExternalLogin method of the AccountContoller as such:

// POST: /Account/ExternalLogin
    [HttpPost]
    [AllowAnonymous]
    [ValidateAntiForgeryToken]
    public ActionResult ExternalLogin(string provider, string returnUrl)
    {
 here-->     ControllerContext.HttpContext.Session.RemoveAll();

        // Request a redirect to the external login provider
        return new ChallengeResult(provider, Url.Action("ExternalLoginCallback", "Account", new { ReturnUrl = returnUrl }));
    }

Could this cause any problems? It seems weird to have to fix Identity out of the box with this line.. (although it is talked about a lot)

EDIT: I've noticed that in the 'IdentityUserLogins' table, it IS showing a LoginProvider of 'Facebook' and the userId is my user.. however, the ApplicationUserId field is null.. upon placing the userid into this field, the 'remove' button shows up in the manage page.... what am I missing? How is the applicationUserID not being entered?.. another fix for the default Identity?

Beau D'Amore
  • 3,174
  • 5
  • 24
  • 56

2 Answers2

1

Found the answer here

I had moved my Identity models into a 'Data' project separate from the web project. The person in this post had a similar issue with his Id's being null as well. A little change to the fluent-api and voila.

var user = modelBuilder.Entity<TUser>()
.ToTable("AspNetUsers");
user.HasMany(u => u.Roles).WithRequired().HasForeignKey(ur => ur.UserId);
user.HasMany(u => u.Claims).WithRequired().HasForeignKey(uc => uc.UserId);
user.HasMany(u => u.Logins).WithRequired().HasForeignKey(ul => ul.UserId);
user.Property(u => u.UserName).IsRequired();

modelBuilder.Entity<TUserRole>()
.HasKey(r => new { r.UserId, r.RoleId })
.ToTable("AspNetUserRoles");

modelBuilder.Entity<TUserLogin>()
.HasKey(l => new { l.UserId, l.LoginProvider, l.ProviderKey})
.ToTable("AspNetUserLogins");

modelBuilder.Entity<TUserClaim>()
.ToTable("AspNetUserClaims");

var role = modelBuilder.Entity<TRole>()
.ToTable("AspNetRoles");
role.Property(r => r.Name).IsRequired();
role.HasMany(r => r.Users).WithRequired().HasForeignKey(ur => ur.RoleId);
Community
  • 1
  • 1
Beau D'Amore
  • 3,174
  • 5
  • 24
  • 56
0

I dared to make changes as follows and it worked beatifully:

//modelBuilder.Entity<IdentityUser>().ToTable("Usuario", "dbo");
 var user = modelBuilder.Entity<IdentityUser>()
           .ToTable("Usuario", "dbo");

            user.HasMany(u => u.Logins).WithRequired().HasForeignKey(ul => ul.UserId);
parismiguel
  • 586
  • 6
  • 16