如何在Node js的服务器端验证谷歌身份验证令牌?



我的前端应用程序使用 gmail 帐户进行身份验证

身份验证成功后,我检索id_token并将其作为授权标头作为持有者令牌发送。

例如 http://localhost:4000/api

授权持有者token_id

nodejs服务器端,我调用以下方法来验证令牌。

exports.verifyUser = function(req, res, next) {
var GoogleAuth = require('google-auth-library');
var auth = new GoogleAuth();
var client = new auth.OAuth2(config.passport.google.clientID, config.passport.google.clientSecret, config.passport.google.callbackURL);
// check header or url parameters or post parameters for token
var token = "";
var tokenHeader = req.headers["authorization"];
var items = tokenHeader.split(/[ ]+/);
if (items.length > 1 && items[0].trim().toLowerCase() == "bearer") {
token = items[1];
}
if (token) {
var verifyToken = new Promise(function(resolve, reject) {
client.verifyIdToken(
token,
config.passport.google.clientID,
function(e, login) {
console.log(e);
if (login) {
var payload = login.getPayload();
var googleId = payload['sub'];
resolve(googleId);
next();
} else {
reject("invalid token");
}
}
)
}).then(function(googleId) {
res.send(googleId);
}).catch(function(err) {
res.send(err);
})
} else {
res.send("Please pass token");
}
}

当我调用上述方法时,我总是收到无效的令牌响应,并出现以下错误。

Error: No pem found for envelope:     {"alg":"RS256","kid":"c1ab5857066442ea01a01601
850770676460a712"}
at OAuth2Client.verifySignedJwtWithCerts (node_modulesgoogle-auth-libr
arylibauthoauth2client.js:518:13)
  • 这是验证令牌的正确方法吗?
  • 我是否以授权持有人的身份发送id_token?还是仅用于授权?
  • 如何将id_token发送到服务器端?通过网址,标题?
  • 我做错了什么?

任何帮助都非常感谢。

OAuth2Client.verifyIdToken

从库源获取参数中的 idToken:

/**
* Verify id token is token by checking the certs and audience
* @param {string} idToken ID Token.
* @param {(string|Array.<string>)} audience The audience to verify against the ID Token
* @param {function=} callback Callback supplying GoogleLogin if successful
*/
OAuth2Client.prototype.verifyIdToken = function(idToken, audience, callback)

您已经传递了整个标头值bearer eyJhbGciOiJSUzI1NiIsImtpZCI6ImMxYWI1OD U3MDY2NDQyZWEwMWEwMTYwMTg1MDc3MDY3NjQ2MGE3MTIifQ因此您必须将标头值拆分为:

var authorization = req.headers["authorization"];
var items = authorization.split(/[ ]+/);
if (items.length > 1 && items[0].trim() == "Bearer") {
var token = items[1];
console.log(token);
// verify token
}

这是验证令牌的正确方法吗?

是的,这是验证令牌的正确方法。对于调试,如果您有任何疑问或快速测试,还可以使用 tokeninfo 端点验证令牌:

https://www.googleapis.com/oauth2/v3/tokeninfo?id_token=XYZ123
  • 我是否以授权持有人的身份发送id_token?还是为了 仅授权?
  • 如何将id_token发送到服务器端?通过 网址,标题?

您可以在授权标头中发送 JWT 令牌,但这可能会导致您有多个授权标头的用例。最好对令牌进行 URL 编码或在正文中嵌入令牌。你可以在这里查看谷歌的例子

此外,谷歌需要以下内容:

  • 令牌必须通过 HTTPS POST 发送
  • 必须验证令牌完整性

为了优化代码,您还可以将 Googleauth对象移动到应用根目录下的app.js,而不是在每次验证令牌时重新定义它。在app.js

var app = express();
var GoogleAuth = require('google-auth-library');
var auth = new GoogleAuth();
app.authClient = new auth.OAuth2(config.passport.google.clientID, config.passport.google.clientSecret, config.passport.google.callbackURL);

verifyUserreq.app.authClient中调用它:

req.app.authClient.verifyIdToken(...)

首先,不要使用Id_Token进行授权。它仅用于身份验证。使用访问令牌进行授权。使用以下链接验证令牌。

https://www.googleapis.com/oauth2/v1/tokeninfo?access_token=${access_token}

我今天终于找到了答案。 Firebase 工具会将原生 Google 连接到第三方登录令牌,然后封装另一层。此时获得的令牌不再是Google提供给我们的原始令牌。

  • 答1:
    • 原始令牌:GoogleDesignInAccount Account = Task.getResult(ApiException.class);
    • Account.getidToken () // This is the original token
  • B1:
    • 火基令牌:FireBaseUser currentUser = Mauth.getCurrentUser ();
    • String token = currentUser.getIdToken(false).getResult().getToken();
  • 答2:
    • 谷歌官方提供了一种验证令牌的方法
  • B2:
    • Firebase 正式提供身份验证令牌方法

我们对上述四个数据点使用代码名称。如果需要在后台验证令牌的有效性,它们必须相互对应,A1 到 A2 和 B1 到 B2。如果使用 A2 验证 B1,它将失败

您现在可以简单地使用 Firebase 验证谷歌身份验证令牌。

首先,创建名为 Firebase-config 的文件并存储您的 Firebase 配置(从 Firebase 设置中获取)。

导入这些:

import { initializeApp } from 'firebase-admin/app';
import { getAuth  } from 'firebase-admin/auth';
import { firebaseConfig } from 'PATH_TO_CONFIG_FILE';  //(importing of your config file that you had created)

初始化:

const defaultApp = initializeApp(firebaseConfig);

谷歌令牌验证功能:

async verifyGoogleId(token) {
const auth = getAuth(defaultApp);
const firebaseUser = await auth.verifyIdToken(token);
if (!firebaseUser) {
throw new error();
}
}

最新更新