在 React 应用程序中使用 Google OAuth2 刷新/使用刷新令牌后保持用户登录

IT技术 javascript reactjs oauth-2.0 google-oauth
2021-05-24 17:11:04

我正在构建一个 React 应用程序,其中功能的一个关键部分是用户可以登录他们的 Google 帐户,然后访问他们最近的 Google Drive/Docs 提及和通知的提要。用户到达我的网站,我与加载谷歌OAuth2用户端我client_idapiKeyscopediscoveryDocs,他们可以点击一个按钮来登录。为了方便起见,我想用户不必重新登录并重新授权使用每次使用应用程序或应用程序刷新时,他们的 Google 帐户,我希望跨会话保存登录信息。为此,我将使用 localStorage 开始,但最终会集成一个像 Firebase 这样的数据库。

在浏览了 JavaScript 客户端 Google OAuth2 文档后,我了解了大多数事情是如何工作的 - 了解存储在 GoogleUser、GoogleAuth 等对象中的数据和方法。我在访问和刷新令牌方面遇到了一些麻烦。我知道您可以通过身份验证用户的信息gapi.auth2.getAuthInstance().currentUser.get()gapi.auth2.getAuthInstance().currentUser.get().getAuthResponse()返回一个对象,其中包含很多我认为我需要的东西id_tokenaccess_token以及像expires_at和 之类的元数据token_type我还看到了grantOfflineAccess()从中提取方法response.code,但我不太确定这些标记化字符串中的哪一个是正确使用的,以及我需要如何使用它。

Google 的这个 FAQ ( https://developers.google.com/api-client-library/javascript/help/faq ) 有点帮助但建议这样做 Refresh the token by calling gapi.auth.authorize with the client ID, the scope and immediate:true as parameters.,但是gapi.auth.authorizeGoogle 在客户端 JS OAuth2 库中指出它与更广泛地使用和大量记录api.auth2.initsignIn

我也从像Google OAuth2 API Refresh Tokens这样的帖子中得到一个模糊的想法,我需要遵循服务器端 OAuth2 说明,我只能refresh_token通过服务器端调用来获得它,但我仍然有点茫然。我会警告并说我更像是一名前端开发人员/设计师,所以我在我的节点和服务器端技能方面摇摇欲坠。

TL; dr:我不知道如何让通过 Google OAuth2 登录的用户在刷新后保持登录状态。我有一个想法,这是因为refresh_tokenaccess_token我访问他们,但我不知道以后该怎么办,在将数据发送到谷歌服务器,获取信息回来,并设置令牌信息为给定的用户而言,当他们返回。

这是我调用 componentDidMount 的方法(基本上是在我的应用程序首次加载时):

loadGoogleClient = () => {

    gapi.load("client:auth2", () => {
        gapi.auth2.init({
          'client_id': my-client-id,
          'apiKey': my-key,
          'scope': "https://www.googleapis.com/auth/drive.readonly",
          'discoveryDocs': ['https://content.googleapis.com/discovery/v1/apis/drive/v3/rest']
        })

            // Listen for sign-in state changes.
        console.log(`User is signed in: ${gapi.auth2.getAuthInstance().isSignedIn.get()}`);
        gapi.client.load("https://content.googleapis.com/discovery/v1/apis/drive/v3/rest")
            .then(() => { console.log("GAPI client loaded for API"); 
                }, (error) => { console.error("Error loading GAPI client for API", error); 
            });
    console.log('Init should have worked');
    });
}

这是我的代码,它位于我的登录按钮上:

authGoogle = () => {
    gapi.auth2.getAuthInstance()
            .signIn({scope: "https://www.googleapis.com/auth/drive.readonly"})
            .then(function() { console.log("Sign-in successful"); },
                  function(err) { console.error("Error signing in", err); });
}
1个回答

如果您使用的是客户端库(gapi api),则不需要刷新令牌......一旦登录,它应该在会话中持续存在并刷新......问题是代码......

1) 将此包含在您index.htmlhead部分中:

<script src="https://apis.google.com/js/api.js"></script>

2)这是一个组件,它将使用gapilib处理身份验证并有条件地呈现一个按钮(代码是不言自明的,但如果您有问题,请问......)

import React from 'react';

class GoogleAuth extends React.Component {
  state = { isSignedIn: null };

  componentDidMount() {
    window.gapi.load('client:auth2', () => {
      window.gapi.client
        .init({
          clientId: '<your client id here...>',
          scope: 'email', // and whatever else passed as a string...
        })
        .then(() => {
          this.auth = window.gapi.auth2.getAuthInstance();
          this.handleAuthChange();
          this.auth.isSignedIn.listen(this.handleAuthChange);
        });
    });
  }

  handleAuthChange = () => {
    this.setState({ isSignedIn: this.auth.isSignedIn.get() });
  };

  handleSignIn = () => {
    this.auth.signIn();
  };

  handleSignOut = () => {
    this.auth.signOut();
  };

  renderAuthButton() {
    if (this.state.isSignedIn === null) {
      return null;
    } else if (this.state.isSignedIn) {
      return <button onClick={this.handleSignOut}>Sign Out</button>;
    } else {
      return <button onClick={this.handleSignIn}>Sign in with Google</button>;
    }
  }
  render() {
    return <div>{this.renderAuthButton()}</div>;
  }
}

export default GoogleAuth;

现在你可以简单地在你的应用程序的任何地方使用这个组件/按钮......这意味着如果你有一个导航组件,只需将它导入那里并将其用作按钮登录/注销......