Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to use Identity user managament with Cordova and OAuth.io?

I want to make a Cordova phone app and a web application. Both the application and the app share the same database.

On the mobile app, the user actions send requests to a web service ( over https ) that writes to the database. On the mobile app, I use https://oauth.io to let the user register and log in with multiple open auth providers. Trying to make it work for facebook, for now.

I just can't figure how to use the Identity user management in that context. Most of the examples I find are in the context of a web app where the user clicks and it calls the account controller. In my case, the oauth.io lib calls facebook, returns an access token, which I pass to my service.

The cordova app passes the accessToken to this method to my server side web service.

var client = new FacebookClient(accessToken);

if (client != null)
{
    dynamic fbresult = client.Get("me");

    if (fbresult["id"] != null)
    {

        var fbid = fbresult["id"].ToString();

        and where do we go from now ?
        how do I insert a new user 

I tried this:

var user = new ApplicationUser() { UserName = fbresult["id"] };
Backend.Controllers.AccountController ac = new Controllers.AccountController();
ac.UserManager.CreateAsync(user);

Doesn't work because the usermanagement object inside the account controller is null. There is an overload of the AccountController constructor but I have a feeling I'm doing this whole thing the wrong way.

Let's say the server side receives a facebook access token. How do use OWIN and Identity user management system from there?

like image 845
Dave Avatar asked Nov 14 '14 19:11

Dave


1 Answers

Ok.

As suggested by a friend, I replaced the controllers etc from the original web api template for the ones in the Identity Sample Project

Here is the method called by the mobile app, with a angular jsonp

[OperationContract]
[WebGet(ResponseFormat = WebMessageFormat.Json)]
public string StartSession(string accessToken)
{
    if (!HttpContext.Current.Request.IsAuthenticated)
    {
        var client = new FacebookClient(accessToken);

        if (client != null)
        {
            dynamic fbresult = client.Get("me");

            if (fbresult["id"] != null)
            {
                string fbid = fbresult["id"].ToString();

                ApplicationUser user = null;

                using (var context = new ApplicationDbContext())
                {
                    user = context.Users.FirstOrDefault(u => u.UserName.ToString() == fbid);
                }

                if (user == null)
                {
                    CreateUserAsync(fbid);
                    return "user created. ";
                }
                else
                {
                    HttpContext.Current.Session["user"] = "holy fuck";                                                  
                    return "user logged in. ";
                }
            }
        }
        return "ok";
    }
    else
    {
        return "already auth !";
    }
}

here is the CreateUserAsync I made

public async System.Threading.Tasks.Task<bool> CreateUserAsync(string fbid)
{

    using (var context = new ApplicationDbContext())
    {

        var newUser = new ApplicationUser() { UserName = fbid, Email = "[email protected]" }; 
        var userManager = new ApplicationUserManager(new UserStore<ApplicationUser>(context));

        try
        {
            var result = await userManager.CreateAsync(newUser, "Admin@123456");
            var test   = await context.SaveChangesAsync();                    

            return result.Succeeded;                   
        }
        catch (Exception ex)
        {

            throw ex;
        }
    }
}

And then, when the mobile app calls back my web service, I can check if the session exists like so:

[OperationContract]
[WebGet(ResponseFormat = WebMessageFormat.Json)]
public async Task<string> TestLogin(int id, string callback)
{

    if (HttpContext.Current.Session["user"] != null)
    {
        return new JavaScriptSerializer().Serialize(new word() { Name = "woot" });        
    }
    else
        return new JavaScriptSerializer().Serialize(new word() { Name = "not logged" });
}

Yea, that's right. A if and a session. Just like I was doin' 13 years ago.

Also, while doing this abomination, I stumbled upon a hangin' problem in the IdentityConfig.cs file.

Apparantly, the problem is known by Microsoft and I guess it is probably fixed in the version 3 of Owin ? But I didn't know about that version 3 at that time, so I followed Program hangs during database initialization .

For some reason, some of the method posted in his solution didn't exist for me. I ended up fixing the code the best I could:

public static void InitializeIdentityForEF(ApplicationDbContext db)
{
    //ApplicationUserManager userManager = HttpContext.Current.GetOwinContext().GetUserManager<ApplicationUserManager>();
    RoleManager<IdentityRole> roleManager = new RoleManager<IdentityRole>(new RoleStore<IdentityRole>(db));

    const string name = "[email protected]";
    const string password = "Admin@123456";
    const string roleName = "Admin";

    IdentityRole adminRole = new IdentityRole(roleName);


    //Create Role Admin if it does not exist
    if (!roleManager.RoleExists(roleName))
    {
        roleManager.Create(adminRole);

        PasswordHasher hasher = new PasswordHasher();

        ApplicationUser adminUser = new ApplicationUser { UserName = name, Email = name, PasswordHash = hasher.HashPassword(password), LockoutEnabled = false };
        db.Users.Add(adminUser);

        IdentityUserRole userRole = new IdentityUserRole() { RoleId  = adminRole.Id, UserId = adminUser.Id };
        adminUser.Roles.Add(userRole);

        var x = db.SaveChanges();

    }

}

Also just in case someone is wondering how to call the svc service from the mobile, here is the code.

(it's a little bit messy, but the important parts are there.) (keep in mind I am using https://oauth.io/ )

$scope.refresh = function () {

$http.jsonp("https://10.0.100.38:6443/Service1.svc/helloworld?id=1&callback=JSON_CALLBACK").success(function JSON_CALLBACK(result) {

    OAuth.popup('facebook')
   .done(function (oauthResult) {

       oauthResult.me() // standardise lesfield firstname, first-name etc
       .done(function (response) {
           alert("3");


           $http.jsonp("https://10.0.100.38:6443/Service1.svc/StartSession?accessToken=" +oauthResult.access_token + "&callback=JSON_CALLBACK").success(function JSON_CALLBACK(result) {
               alert("done " +result); // StartSession serverside success ");

    }).error(function (data, status, headers, config) {
                   alert("icierror2" +data + " " +status + " " +headers + " " + config);

               $scope.status = status;
               });
       }).fail(function (error) {
           alert("icierror3 " +error);
       });
       })
   .fail(function (error) {
       console.log(error);
});

    alert(result.Name); // result de la svc request over https

    }).error(function (data, status, headers, config) {
        alert("icierror" +data + " " +status + " " + headers + " " +config);

    $scope.status = status;
});

Problems

As of now, I am not creating a Login, only a user is created.

Also, the project's OWIN version is 2.0, and apparantly, a 3.0 exists.

To be honest, the more I read online the more I feel like everything I've done is a big hack around the right way to do it. I just couldn't figure it out. This is thing is incredibly huge, confusing, chaothic and broken. Yea, I've added an opinion to my answer.

like image 197
Dave Avatar answered Oct 12 '22 12:10

Dave