Oauth 验证G+;客户端登录后,服务器端的用户

Oauth 验证G+;客户端登录后,服务器端的用户,oauth,google-plus,google-oauth,Oauth,Google Plus,Google Oauth,我正在尝试设置一个按钮,允许人们在我的网站上购买物品 客户端身份验证看起来非常简单,但我很难理解服务器端身份验证是如何工作的。在这种情况下,他们将客户端“code”参数传递给服务器,在服务器上可以用它换取访问令牌,然后可以使用访问令牌查看用户的好友列表 但是我不想看到用户朋友的列表。我只是想确定客户实际上就是他们声称的那个人 在检索令牌之后,示例代码将令牌放入会话中,并且似乎使用令牌的存在来验证用户是否经过身份验证。这样正确/安全吗?我的服务器是否应该在购买时以某种方式(如何)重新验证令牌?我是

我正在尝试设置一个按钮,允许人们在我的网站上购买物品

客户端身份验证看起来非常简单,但我很难理解服务器端身份验证是如何工作的。在这种情况下,他们将客户端“code”参数传递给服务器,在服务器上可以用它换取访问令牌,然后可以使用访问令牌查看用户的好友列表

但是我不想看到用户朋友的列表。我只是想确定客户实际上就是他们声称的那个人


在检索令牌之后,示例代码将令牌放入会话中,并且似乎使用令牌的存在来验证用户是否经过身份验证。这样正确/安全吗?我的服务器是否应该在购买时以某种方式(如何)重新验证令牌?我是否应该在每次请求时不断与Google重新验证令牌?(希望不是?

在执行购买之前,您可能希望通过安全地将用户id从客户端传递到服务器,并根据存储凭据的用户id进行验证,来验证用户是否是您期望的用户。这为防止重播攻击提供了额外的保护,在重播攻击中,攻击者通过劫持会话假装是您站点的用户,这是在接受用户付款之前最相关的检查

我不会仅仅依靠用户验证作为防止欺诈的机制。您应该使用安全的支付系统,如和follow

提醒一下,每次初始化缓存的凭据时,应使用OAuth2 v2端点检查令牌。检查每个请求似乎有点过分,因为您应该使用已验证并存储在服务器端的缓存凭据。最多,您可以在更新访问令牌时执行检查,但如果您信任刷新令牌,则在创建帐户并设置刷新令牌时执行检查应该足够安全

除了在创建帐户时进行用户id验证外,还将执行以下步骤:

  • 验证客户是否是您期望的客户。这可以防止伪造的访问令牌被传递到您的应用程序,从而有效地代表攻击者使用您的配额发出请求
  • 验证该帐户是否由您的应用程序创建,这在代表用户创建其他帐户的情况下是有效的
正如您在链接文章中提到的,中的示例代码应该充分演示如何使用各种编程语言执行这些检查以获得帐户授权

在HTML/JS客户机中,以下代码显示了在何处检索用户ID(值,而不是特殊字符串“me”),以传递给connect方法以验证Google+用户ID:

  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(
          $('<p><img src=\"' + profile.image.url + '\"></p>'));
      $('#profile').append(
          $('<p>Hello ' + profile.displayName + '!<br />Tagline: ' +
          profile.tagline + '<br />About: ' + profile.aboutMe + '</p>'));
      if (profile.cover && profile.coverPhoto) {
        $('#profile').append(
            $('<p><img src=\"' + profile.cover.coverPhoto.url + '\"></p>'));
      }
    });
在Java示例中执行这些检查的相关代码如下所示:

      // 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());
    }

在示例中,ClientID来自Google API控制台,对于您的应用程序来说是不同的。

我发布了一个相关问题,因为我认为Facebook API实现这一点的标准方法是使用signed_请求参数,但Google似乎没有类似的参数。1) “传递用户id”是指“代码”参数吗?还是用户ID?2) “根据存储的凭据验证”示例代码不存储凭据。到底应该存储什么?要多久?(数据库?会话?)。是吗?(比如说)Java示例的哪一行符合您的要求?1)在示例的HTML/JS客户端(index.HTML)的connect方法中,您会注意到Google+id作为GET参数传递,并使用令牌信息进行验证。2) 这些示例模拟使用会话存储存储用户凭据的操作,并使用存储的访问/刷新令牌重新创建授权状态。刷新令牌不会过期,因此除非用户断开其帐户的连接,否则应该安全地将其保留。访问令牌在3600秒后过期,因此应仅在过期时更新。第153-183行正在执行Java示例中的检查。最后一条注释是,如果您想查看令牌和凭证应该如何持久化的更全面的示例,PhotoHunt示例将更好地演示这一点。在此处查看saveTokenForUser:
      // 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());
    }