Authenticating G+ users on the server side, after client-side login

前端 未结 1 681
半阙折子戏
半阙折子戏 2020-12-18 07:03

I\'m trying to set up a Sign in with Google button that will allow people to purchase things on my website.

Client-side authentication looks pretty straightforward,

1条回答
  •  不思量自难忘°
    2020-12-18 07:44

    What you might want to do before performing a purchase is to verify the user is who you expect them to be by securely passing the user id from the client to your server and verifying it against the user id for the stored credentials. This offers additional protection against replay attacks where an attacker is pretending to be your site's user by hijacking their session and is the most relevant check to make before accepting payment from the user.

    I would not rely on user validation alone as a mechanism for protection against fraud. You should use a secure payment system such as the Google Commerce platform and follow the best practices for commerce.

    As a reminder, the OAuth2 v2 endpoint should be used to check your token every time the cached credentials are initialized. Checking on every request seems a bit excessive because you should be using cached credentials that have already been validated and stored server-side. At most, you could perform the checks when you update an access token but if you trust your refresh token, you should be sufficiently safe if you perform the checks when you create the account and set that refresh token.

    The following steps are taken in addition to the user id validation upon account creation:

    • Verify the client is who you expect it to be. This protects you against forged access tokens being passed to your app for effectively making requests on behalf of the attacker using your quota.
    • Verify that the account was created by your application, this protects you and your users against cross-site request forgery in cases where additional accounts are created on behalf of a user.

    As mentioned in your linked post, the sample code in the Google+ quickstarts should sufficiently demonstrate how to perform these checks in a variety of programming languages for account authorization.

    Within the HTML/JS client, the following code shows where the userId (value, as opposed to the special string "me") is retrieved for passing to the connect method to verify the Google+ userId:

      var request = gapi.client.plus.people.get( {'userId' : 'me'} );
      request.execute( function(profile) {
          $('#profile').empty();
          if (profile.error) {
            $('#profile').append(profile.error);
            return;
          }
          helper.connectServer(profile.id);
          $('#profile').append(
              $('

    ')); $('#profile').append( $('

    Hello ' + profile.displayName + '!
    Tagline: ' + profile.tagline + '
    About: ' + profile.aboutMe + '

    ')); if (profile.cover && profile.coverPhoto) { $('#profile').append( $('

    ')); } });

    ... and the following code shows the Google+ id being passed.

    connectServer: function(gplusId) {
      console.log(this.authResult.code);
      $.ajax({
        type: 'POST',
        url: window.location.href + '/connect?state={{ STATE }}&gplus_id=' +
            gplusId,
        contentType: 'application/octet-stream; charset=utf-8',
        success: function(result) {
          console.log(result);
          helper.people();
        },
        processData: false,
        data: this.authResult.code
      });
    }
    

    The relevant code performing these checks in the Java sample is as follows:

          // Check that the token is valid.
          Oauth2 oauth2 = new Oauth2.Builder(
              TRANSPORT, JSON_FACTORY, credential).build();
          Tokeninfo tokenInfo = oauth2.tokeninfo()
              .setAccessToken(credential.getAccessToken()).execute();
          // If there was an error in the token info, abort.
          if (tokenInfo.containsKey("error")) {
            response.status(401);
            return GSON.toJson(tokenInfo.get("error").toString());
          }
          // Make sure the token we got is for the intended user.
          if (!tokenInfo.getUserId().equals(gPlusId)) {
            response.status(401);
            return GSON.toJson("Token's user ID doesn't match given user ID.");
          }
          // Make sure the token we got is for our app.
          if (!tokenInfo.getIssuedTo().equals(CLIENT_ID)) {
            response.status(401);
            return GSON.toJson("Token's client ID does not match app's.");
          }
          // Store the token in the session for later use.
          request.session().attribute("token", tokenResponse.toString());
          return GSON.toJson("Successfully connected user.");
        } catch (TokenResponseException e) {
          response.status(500);
          return GSON.toJson("Failed to upgrade the authorization code.");
        } catch (IOException e) {
          response.status(500);
          return GSON.toJson("Failed to read token data from Google. " +
              e.getMessage());
        }
    

    In the samples, the ClientID came from the Google API console and will be distinct for your application.

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