How to create a parse _User account from a Android Google token?

前端 未结 2 1386
滥情空心
滥情空心 2021-01-05 13:40

I\'ve found some fragments of useful information.

http://blog.parse.com/announcements/bring-your-own-login/ shows me how to login an Android app once I have

相关标签:
2条回答
  • 2021-01-05 13:48

    Steps:

    1. Get the Google token
    2. Send the Google token to your Parse back-end to validate
    3. Use the validated Google token to create a Parse session token
    4. Use the Parse session token to allow users to access the app

    (1): See the guide: https://developers.google.com/identity/sign-in/android/sign-in


    (2): Send the ID token to your back-end server (in this case Parse).

    //sending the token to the backend
            String backendApiUrlToGenerateSessionToken = your_url_with_cloud_code_to_generate_session_token;
            Log.i("URL: ", backendApiUrlToGenerateSessionToken);
    
            RequestQueue newRequestQueue = Volley.newRequestQueue(this);
    
            JSONObject getSessionTokenJsonRequestBody = new JSONObject();
            //back-end requires the token and Google client ID to be verified
            try {
                getSessionTokenJsonRequestBody.put("idToken", idTokenFromGoogle);
                getSessionTokenJsonRequestBody.put("GClientId", your_google_client_id);     //find it in google-services.json file
            } catch (JSONException e) {
                e.printStackTrace();
            }
    
            final String requestBody = getSessionTokenJsonRequestBody.toString();
    
            JsonObjectRequest jsonObjectRequest = new JsonObjectRequest(Request.Method.POST, backendApiUrlToGenerateSessionToken, getSessionTokenJsonRequestBody,
                    new Response.Listener<JSONObject>() {
                        @Override
                        public void onResponse(JSONObject response) {
                            //success callback
                            //set current user and continue
                            try {
                                ParseUser.becomeInBackground(response.getString("result"), new LogInCallback() {
                                    @Override
                                    public void done(ParseUser user, ParseException e) {
                                        if (user != null){
                                            //successfully logged in, take the user to the last page they were on
                                            finish();
                                        }else{
                                            //error
                                            Log.e("Login error: ", e.getMessage());
                                            //show error dialog, prompt user to login again
    
                                        }
                                    }
                                });
                            } catch (JSONException e) {
                                e.printStackTrace();
                            }
    
                        }
                    },
                    new Response.ErrorListener() {
                        @Override
                        public void onErrorResponse(VolleyError error) {
                            //error callback
                            int  statusCode = error.networkResponse.statusCode;
                            NetworkResponse response = error.networkResponse;
    
                            Log.d("Error Response req: ","" + statusCode + " " + response.data.toString());
    
                        }
                    })
            {
                @Override
                public Map<String, String> getHeaders(){
                    Map<String, String> headers = new HashMap<>();
                    //post parameters
                    headers.put("X-Parse-Application-Id", getResources().getString(R.string.parse_app_id));
                    headers.put("X-Parse-REST-API-Key", getResources().getString(R.string.parse_rest_api_key));
                    headers.put("Content-Type", "application/json");
                    return headers;
                }
    
                @Override
                public byte[] getBody(){
                    try {
                        String body;
                        if (requestBody == null) body = null;
                        else body = String.valueOf(requestBody.getBytes("utf-8"));
                        return requestBody == null ? null : requestBody.getBytes("utf-8");
                    } catch (UnsupportedEncodingException e) {
                        e.printStackTrace();
                        return null;
                    }
                }
            };
            newRequestQueue.add(jsonObjectRequest);
    

    (3): We've sent the token to our back-end, now we need to validate the token and generate our Parse session token in our back-end. Credit to @Amit http://pastebin.com/133LVYbm included logic to handle logged out users and subsequent login from the same Google account

    //generating a random password
    function getRandomString(){
        var chars = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXTZ";
        var string_length = 10;
        var randomstring = '';
    
        for (var i=0; i<string_length; i++) {
            var rnum = Math.floor(Math.random() * chars.length);
            randomstring += chars.substring(rnum,rnum + 1);
        }
        return randomstring;
    }
    
    Parse.Cloud.define("getSessionToken", function(request, response) {
        console.log(request);
        console.log(request.params.accessToken);
        console.log(request.params.GClientId);
        Parse.Cloud.useMasterKey();
    
    //Verifying token (id Token)
    var authTokenVerificationURL = "https://oauth2.googleapis.com/tokeninfo?id_token=" + request.params.idToken;
    console.log(authTokenVerificationURL);
    Parse.Cloud.httpRequest({
        url:authTokenVerificationURL
    }).then(function(httpResponse){
        //Success
        //console.log("success httpResponse: " + httpResponse.text);
    
        //Verify if token is generated from our client
        var gAudience = httpResponse.data.aud;
        if(gAudience == request.params.GClientId) {
            console.log("Verified: Token is generated from our app");
    
            var user_emailId = httpResponse.data.email; 
            var user_username = httpResponse.data.name;
            //console.log(user_emailId);
    
            /*
            * 1. User signing up for the first time
            * 2. User already signed up logging in
            */
    
            //Check if User account exists for the emailId
            var query = new Parse.Query(Parse.User);
            query.equalTo("email",user_emailId);
            query.first({
                success: function(user) {
    
                    //if the user exists, they could have logged out so no sessionToken is available so we'll need to log them in again
                    if(user) {
                        console.log("User found with Username: " + user.getUsername() + ", objectId: " + user.id);
    
                        //Generate the Session Token
                        var sessionToken = user.getSessionToken();
                        if(sessionToken) {
                            console.log("SessionToken: " + sessionToken);
                            response.success(sessionToken);
                        }else {
                            //create a new session - login (user can signup then log-out which deletes the session)
                            var newRandomPassword = getRandomString();
                            user.set("password", newRandomPassword);
                            user.save(null, {useMasterKey : true}).then(function(user){
                                Parse.User.logIn(user.get("username"), newRandomPassword).then(function(user){
                                    var sessionToken = user.getSessionToken();
                                    response.success(sessionToken);
                                }, function(error){
                                    response.error("Cannot create session");
                                })
                            }, function(error){
                                response.error("Unable to save user data");
                            });
    
                        }
    
                    }else {
                        console.log("User not found, Creating new account for user with emailId: " + user_emailId);
    
                        //Create New Account
                        var nUser = new Parse.User();
                        nUser.set("username",user_username);
                        nUser.set("password",getRandomString());
                        nUser.set("email",user_emailId);
                        nUser.signUp(null,{
                            success: function(user) {
                                console.log("New account created for user with emailID: " + user_emailId);
    
                                //Generate the Session Token
                                var sessionToken = user.getSessionToken();
                                console.log("SessionToken: " + sessionToken);
                                response.success(sessionToken);
                            },
                            error: function(user, error) {
                                console.log("Failed to create a new account for emailID: " + user_emailId);
                                console.log("User: " + user + ", Error: " + error);
                                response.error(error);
                            }
                        });
                    }
    
    
                },
                error: function(user, error) {
                    console.log("Query to fetch user failed");
                    console.log("User: " + user + ", Error: " + error);;
    
                    response.error(error);  
                },
                userMasterKey:true
            });
    
    
    
        }else { //Client has not login from our app
            console.log("Google AudienceID: " + gAudience + "\n AppClientId: " + request.params.GClientId);
            response.error('Invalid Audience');
        }
    
    },function(httpResponse) {
        //Error
        console.log("Failed httpResponse: " + httpResponse.text);
        console.error('Request Failed with response code' + httpResponse.status);
        response.error('Failed to verify access token');
    });
    
    });
    

    (4) Logic is in step (2) when the requestQueue returns the response we call the becomenbackground() method which saves the session and allows us to get the currently logged in user

    0 讨论(0)
  • 2021-01-05 14:05

    Note: This answer does not apply to the Open Source Parse Server, as it uses revocable sessions only. Check out parse-server/issues/1392 for further update

    Update (Jan-2016):

    You need to turn off Revocable Session in order to call getSessionToken on Parse.User. Go to App Settings >> Users >> Turn off Require revocable sessions. This is not new in 2016, but at the time of giving answer, the author did not know of this change.


    I will break into 2 cases for easier to follow: New User and Returning User.

    1. New User

    The flow is as below:

    1. User authorizes and a token is acquired
    2. We create a new user with a random password

    You can create a ParseUser using following code inside the newChooseAccountIntent() method that return email.

    ParseUser user = new ParseUser();
    user.setUsername(mEmail);
    user.setPassword(randomPassword);
    user.setEmail(mEmail);
    user.signUpInBackground(new SignUpCallback() {
      public void done(ParseException e) {
        if (e == null) {
          // Hooray! Let them use the app now.
        } else {
          // Sign up didn't succeed. Look at the ParseException
          // to figure out what went wrong
        }
      }
    });
    

    2. Returning User

    This is the where most of people stuck, as I researched over the Internet. The flow is as below:

    1. User authorizes and the app gets a token
    2. We pass this token to Cloud Code to validate. We need to check if this token is signed by Google and if it is meant for us (android-developers (2013)).
    3. After you can verify that the token is valid, you can query for the user in Cloud Code using Parse.Cloud.useMasterKey() method and return the session key by using getSessionToken() method on the query result.
    4. Use the session key to save login state on disk by calling becomeInBackground method

    To validate the token, you can send Parse.Cloud.httprequest to this endpoint: https://www.googleapis.com/oauth2/v3/tokeninfo?access_token=. This is instructed in Google Identity Documentation. You will receive data as below:

    {
     "iss": "https://accounts.google.com",
     "sub": "110169484474386276334",
     "azp": "1008719970978-hb24n2dstb40o45d4feuo2ukqmcc6381.apps.googleusercontent.com",
     "email": "billd1600@gmail.com",
     "at_hash": "X_B3Z3Fi4udZ2mf75RWo3w",
     "email_verified": "true",
     "aud": "1008719970978-hb24n2dstb40o45d4feuo2ukqmcc6381.apps.googleusercontent.com",
     "iat": "1433978353",
     "exp": "1433981953"
    }
    

    Things need to compare are "aud", "azp" and "email" which are translated as audience, authorized party and email.

    To query for the current user on Cloud Code:

    var query = new Parse.Query(Parse.User);
    query.equalTo("email",mEmail);
    query.first({
      success: function(user) {
        // Use user..getSessionToken() to get a session token
      },
      error: function(user, error) {
        //
      },
      useMasterKey: true
    });
    

    Note: Make sure you have following scope so that the email will show up when you check on Cloud Code: https://www.googleapis.com/auth/plus.profile.emails.read

    0 讨论(0)
提交回复
热议问题