1
votes

I am looking for some help regarding Azure Mobile Services authentication using one of the built in providers (google, facebook, etc). specifically, a way to set the UserId of the MobileServiceUser to the Id I have in my backend sql database for that user.

Background:

I am working on an application that consists of a mobile app that interfaces with an azure mobile service .net backend and an azure MVC web app that uses the same database as the mobile service.

the general workflow for creating a new user and logging in is:

  • A new end user is created by an "admin" using the MVC web app that the end user does not have access to.
  • An Id is created in the sql database for this new end user.
  • Additional data for that end user is created in other related tables using this newly created user Id.
  • The end user is then required to log into the mobile service using their mobile device to view and update their data.

the problem that I have is that the UserId in the MobileServiceUser is a UserId created by the login provider. When I query data in the mobile service, I use the UserId from the TableController's ServiceUser to make sure the end user only interacts with their data.

I would like to set the UserId for the MobileServiceUser to the Id that was created in the sql database for the end user when the "admin" created it.

UserId is read only so Im assuming I would have to do this on the server side.

So to start, I created a CustomGoogleLoginProvider class that inherits from GoogleLoginProvider and overrode the CreateCredentials method. In that method I attempt to extract the username from the ClaimsIdentity, use that username to get the Id from the database, then set the UserID of the resulting ProviderCredentials to that Id:

 public override ProviderCredentials CreateCredentials(ClaimsIdentity claimsIdentity)
    {
        var username = claimsIdentity.FindFirst(ClaimTypes.Name).Value;

        var context = new MyAppContext();

        var user= context.Users.FirstOrDefault(p => p.Email == username);

        var result =  base.CreateCredentials(claimsIdentity);

        result.UserId = user.Id;

        return result;
    }

I have a few questions:

  1. Is it safe to change the UserId in this manner?
  2. If not, is there a better way?
  3. I do not know how to run the mobile service authentication code interactively so I cant tell if it is actually working. Can anyone let me know if claimsIdentity.FindFirst(ClaimTypes.Name).Value actually returns the username that the was used when logging in via the provider? is this the same for Google, Facebook, twitter, and Microsoft providers?

Thanks for your time!

1

1 Answers

0
votes

Personally I would recommend the following. Use your own data structure for Users (which you are already doing I believe) and add fields for login providers to that table.

Example:

User

  • Id
  • Some Information
  • Microsoft Account Id
  • Facebook Account Id

If a users logs into your service with any of your supported account providers you can just query your User table for the user that has been associateed with the provider Id.

Here's a reduced version of what my CreateCredentials looks like (albeit for Microsoft account, but there is really not much of a difference)

public override ProviderCredentials CreateCredentials(ClaimsIdentityclaimsIdentity)
{
    string microsoftAccoundId = claimsIdentity.FindFirst(ClaimTypes.NameIdentifier).Value;
    var account = context.Authors.Where(a => a.MicrosoftAccountId == microsoftAccoundId).FirstOrDefault();

    // set our own account id
    var microsoftCredentials = base.CreateCredentials(claimsIdentity);
    microsoftCredentials.UserId = this.TokenHandler.CreateUserId(base.Name, account.Id);

    return microsoftCredentials;
}

Edit: Totally forgot the questions:

  1. I would say yes.
  2. Not sure.
  3. I'm not sure if you can actually get the username like that. You can however get the account id with ClaimTypes.NameIdentifier instead.