Google OAuth2:“verifyIdToken 方法需要 ID 令牌”错误

问题描述 投票:0回答:1

我有一个应用程序,Google OAuth2 以前运行良好,但现在似乎有些东西发生了变化,它不再工作了。当我尝试使用 Google 登录时,我在响应正文中收到以下消息:

The verifyIdToken method requires an ID Token

起初我认为问题可能出在 Node 后端的

google-auth-library
实现上,但是,据我所知,它似乎没有改变,除非我遗漏了一些东西。

这是我在前端的内容:

index.js

import React from "react";
import ReactDOM from "react-dom";
import App from "./App";
import AuthProvider from "./context/AuthContext";
import { GoogleOAuthProvider } from "@react-oauth/google";

ReactDOM.render(
  <GoogleOAuthProvider clientId={process.env.REACT_APP_GOOGLE_CLIENT_ID}>
  <AuthProvider>
    <App />
  </AuthProvider>
  </GoogleOAuthProvider>,
  document.getElementById("root")
);

登录.js

import { useNavigate, useLocation } from "react-router-dom";
import { AuthContext } from "../context/AuthContext";
import { GoogleLogin } from "@react-oauth/google";
import axios from "../config/axiosConfig";

const isProduction = process.env.NODE_ENV === "production";
const authContext = useContext(AuthContext);
const navigate = useNavigate();
const { state } = useLocation();
const [message, setMessage] = useState(null);

function Login() {
  function handleSuccess(response) {
    axios
      .post("/api/auth/google", { token: response.tokenId })
      .then((res) => {
        const { user, isAuthenticated } = res.data;

        authContext.setUser(user);
        authContext.setIsAuthenticated(isAuthenticated);
        navigate(state?.path || "/diary");
      })
      .catch((err) => {
        console.log(err);
      });
  }

  function handleFailure(response) {
    setMessage("Authentication failed");
  }
  
  return (
    <GoogleLogin
      className="google-btn"
      redirectUri={
      isProduction
        ? process.env.REACT_APP_CLIENT_URL_PROD
        : process.env.REACT_APP_CLIENT_URL_DEV
      }
      onSuccess={handleSuccess}
      onError={handleFailure}
      theme="filled_blue"
      width="312px"
    />
  )
}

export default Login;

并且,在服务器端,我有这个:

auth.controller.js

const { OAuth2Client } = require("google-auth-library");
const client = new OAuth2Client(process.env.GOOGLE_CLIENT_ID);

const google = async (req, res) => {
  try {
    const { token } = req.body;

    const ticket = await client.verifyIdToken({
      idToken: token,
      audience: process.env.GOOGLE_CLIENT_ID,
    });

    const { given_name, family_name, email, sub } = ticket.getPayload();

    User.findOne({ email: email }, (err, user) => {
      if (!user) {
        const newUser = new User({
          first_name: given_name,
          last_name: family_name,
          email: email,
          googleId: sub,
        });

        newUser.save();

        generateTokens(newUser, res);

        res.status(201).json({
          isAuthenticated: true,
          user: given_name,
        });
      } else if (user && !user.googleId) {
        user.googleId = sub;
        user.save();

        generateTokens(user, res);

        res.status(200).json({
          isAuthenticated: true,
          user: user.first_name,
        });
      } else {
        console.log(err);
      }
    });
  } catch (error) {
    res.status(500).json({ success: false, message: error.message });
  }
};
reactjs node.js oauth-2.0 google-oauth token
1个回答
0
投票

它需要的只是对如何从新的

@react-oauth/google
组件传递数据以及 Node 后端如何处理数据进行一些调整。

首先,确保您的应用程序由

GoogleOAuthProvider
包装,就像之前在
index.js
中所做的那样。这里没有什么新鲜事:

import { GoogleOAuthProvider } from "@react-oauth/google";

ReactDOM.render(
  <GoogleOAuthProvider clientId={process.env.REACT_APP_GOOGLE_CLIENT_ID}>
    <App />
  </GoogleOAuthProvider>,
  document.getElementById("root")
);

请注意,

clientId
已被通过。

当您单击 Google 登录按钮时,如果没有出现任何问题,它将将从 Google 返回的凭据响应传递给

handleSuccess
函数:

function Login() {

  // HANDLE GOOGLE AUTHENTICATION
  function handleSuccess(credentials) {
    axios
      .post("/api/auth/google", credentials)
      .then((res) => {
        // do something...
      })
      .catch((err) => {
        console.log("Authentication failed: " + err);
      });
  }

  return (
    <GoogleLogin
      onSuccess={(credentialResponse) => {
        handleSuccess(credentialResponse);
      }}
      onError={handleFailure}
      theme="filled_blue"
      width="312px"
    />
  )
}

export default Login;

这就是在

POST
请求中实际传递到后端的内容:

凭证

{
  "clientId": "<YOUR_CLIENT_ID>",
  "credential": "<ID_TOKEN>",
  "select_by": "btn"
}

现在,这就是您在处理来自前端的

POST
请求时希望在后端实现的目标。一旦您能够正确验证凭据,您就可以对其进行解码以获取用户信息并根据需要操作数据:

const { OAuth2Client } = require("google-auth-library");
const client = new OAuth2Client(process.env.GOOGLE_CLIENT_ID);

const google = async (req, res) => {
  const { credential, clientId } = req.body;

  try {
    const ticket = await client.verifyIdToken({
      idToken: credential,
      audience: clientId,
    });

    const { given_name, family_name, email, sub } = ticket.getPayload();

    // do something...
  } catch (error) {
    res.status(500).json({ success: false, message: error.message });
  }
};

这是解码后的凭据(更多信息此处):

{
  "iss": "https://accounts.google.com", // The JWT's issuer
  "nbf":  161803398874,
  "aud": "314159265-pi.apps.googleusercontent.com", // Your server's client ID
  "sub": "3141592653589793238", // The unique ID of the user's Google Account
  "hd": "gmail.com", // If present, the host domain of the user's GSuite email address
  "email": "[email protected]", // The user's email address
  "email_verified": true, // true, if Google has verified the email address
  "azp": "314159265-pi.apps.googleusercontent.com",
  "name": "Elisa Beckett",
                            // If present, a URL to user's profile picture
  "picture": "https://lh3.googleusercontent.com/a-/e2718281828459045235360uler",
  "given_name": "Elisa",
  "family_name": "Beckett",
  "iat": 1596474000, // Unix timestamp of the assertion's creation time
  "exp": 1596477600, // Unix timestamp of the assertion's expiration time
  "jti": "abc161803398874def"
}
© www.soinside.com 2019 - 2024. All rights reserved.