Google People API:请求具有无效的身份验证凭据 - 未设置授权承载标头
Posted
技术标签:
【中文标题】Google People API:请求具有无效的身份验证凭据 - 未设置授权承载标头【英文标题】:Google People API: Request had invalid authentication credentials - Authorization Bearer header not setting up 【发布时间】:2021-04-06 07:16:51 【问题描述】:我正在尝试为我正在开发的聊天应用程序实现这个 Google People api。 people API 文档只有这个例子 - https://github.com/googleworkspace/node-samples/blob/master/people/quickstart/index.js
我做了一些更改以将其与我的项目集成。
// imports
const app = express();
app.use(cookieParser());
const SCOPES = ['https://www.googleapis.com/auth/contacts.readonly'];
const people = google.people('v1');
let credentials, oAuth2Client;
fs.readFile('./client_secret.json', async (err, content) =>
if (err) return console.error(err);
credentials = JSON.parse(content);
const client_secret, client_id, redirect_uris = credentials.web;
oAuth2Client = new google.auth.OAuth2(
client_id, client_secret, redirect_uris[1]);
);
app.get("/auth/google", (req, res) =>
console.log(req.cookies);
res.cookie("sample_cookie", "sample_value");
const authUrl = oAuth2Client.generateAuthUrl(
access_type: 'offline',
scope: SCOPES,
);
console.log('Authorize this app by visiting this url:', authUrl);
res.redirect(authUrl);
);
app.get("/contacts", (req, resp) =>
if (req.cookies.access_token && req.cookies.refresh_token)
const token =
access_token: req.cookies.access_token,
refresh_token: req.cookies.refresh_token,
scope: req.cookies.scope,
token_type: "Bearer",
expiry_date: req.cookies.expiry_date,
oAuth2Client.setCredentials(token);
const service = google.people( version: 'v1', oAuth2Client );
service.people.connections.list(
resourceName: 'people/me',
pageSize: 10,
personFields: 'names,emailAddresses,phoneNumbers',
, (err, res) =>
if (err) return resp.send(err);
const connections = res.data.connections;
if (connections)
connections.forEach((person) =>
if (person.names && person.names.length > 0)
resp.write(person.names);
else
resp.write('No display name found for connection.');
);
else
resp.write('No connections found.');
resp.end();
);
else
res.send("Something's wrong yet.")
)
app.get(["/auth/google/callback", "authorized"], async (req, res) =>
const code = req.query.code;
oAuth2Client.getToken(code, (err, token) =>
if (err) return console.error('Error retrieving access token', err);
oAuth2Client.setCredentials(token);
res.cookie("access_token", token.access_token);
res.cookie("refresh_token", token.refresh_token);
res.cookie("scope", token.scope);
res.cookie("token_type", token.token_type);
res.cookie("expiry_date", token.expiry_date);
res.send("Done.")
)
)
app.listen(3000, () =>
console.log("running");
)
但我收到 401:未授权。我对前一个(Google)示例所做的所有更改只是我没有将详细信息保存到令牌,而是将它们保存为 cookie,并添加了从浏览器访问它的路由。 Google 提供的示例按预期工作。我所做的更改在授权点之前也有效,但是当尝试访问联系人路由时,它会返回以下响应。
这是我收到的回复(仅包含我认为必要的详细信息):
"response":
"config":
"oAuth2Client":
"credentials":
"access_token": "my_access_token",
"refresh_token": "my_refresh_token",
"scope": "https://www.googleapis.com/auth/contacts.readonly",
"token_type": "Bearer",
"expiry_date": 1609256514576
,
"redirectUri": "http://localhost:3000/auth/google/callback",
,
"url": "https://people.googleapis.com/v1/people/me/connections?pageSize=10&personFields=names%2CemailAddresses%2CphoneNumbers",
"method": "GET",
"headers":
"Accept-Encoding": "gzip",
"User-Agent": "google-api-nodejs-client/0.7.2 (gzip)",
"Accept": "application/json"
,
,
"data":
"error":
"code": 401,
"message": "Request is missing required authentication credential. Expected OAuth 2 access token, login cookie or other valid authentication credential. See https://developers.google.com/identity/sign-in/web/devconsole-project.",
"errors": [
"message": "Login Required.",
"domain": "global",
"reason": "required",
"location": "Authorization",
"locationType": "header"
],
"status": "UNAUTHENTICATED"
,...
我尝试调试代码。我什么也抓不住。但我注意到的一件事是,在上述响应中,我没有设置 Authorization 标头。在来自谷歌文档示例的成功 API 请求中,我收到了
"config":
"url": "https://people.googleapis.com/v1/people/me/connections?pageSize=10&personFields=names%2CemailAddresses%2CphoneNumbers",
"method": "GET",
"headers":
"Accept-Encoding": "gzip",
"User-Agent": "google-api-nodejs-client/0.7.2 (gzip)",
"Authorization": "Bearer access-code",
"Accept": "application/json"
,
,
"data":
"connections": [...
我不明白为什么我的代码没有设置 Authorization 标头,而且 OAuthClient 和凭据字段也不存在于这个成功的响应中。如果不是人员 api,我在联系人路由中尝试类似下面的操作,或者在邮递员中使用 Bearer 令牌发出 GET 请求,我会得到正确的响应。
let bearer = `Bearer $req.cookies.access_token`;
request(
url: 'https://people.googleapis.com/v1/people/me/connections?pageSize=10&personFields=names%2CemailAddresses%2CphoneNumbers',
headers:
'Authorization': bearer
, (err, res) =>
if (err)
console.error(err);
else
resp.send(res);
);
我正确收到了回复。但我不想这样做。我无法弄清楚我的代码有什么问题,或者是否有人可以提供任何其他工作示例......我也尝试使用 passport.js,但我得到了同样的 401 未经授权的错误。
// passport-setup.js
const passport = require('passport');
const GoogleStrategy = require('passport-google-oauth20').Strategy;
passport.serializeUser(function (user, done)
done(null, user);
);
passport.deserializeUser(function (user, done)
done(null, user);
);
passport.use(new GoogleStrategy(
clientID: "client-id",
clientSecret: "client-secret",
callbackURL: "http://localhost:3000/auth/google/callback",
passReqToCallback: true
,
function (req, accessToken, refreshToken, otherTokenDetails, profile, done)
req.session.accessToken = accessToken;
req.session.refreshToken = refreshToken;
req.session.scope = otherTokenDetails.scope;
req.session.token_type = otherTokenDetails.token_type;
req.session.expiry_date = new Date().getTime() + otherTokenDetails.expires_in;
return done(null, profile);
));
index.js
// importing express, cors, bodyParser, passport, cookieSession, passport setup and googleapis
const app = express();
const people = google.people('v1');
// app.use(cors, bodyParser, cookieSession, passport init and session)
const isLoggedIn = (req, res, next) =>
if (req.user)
next();
else
res.sendStatus(401);
app.get("/success", isLoggedIn, (req, resp) =>
const oAuth2Client = new google.auth.OAuth2(id, secret and url...)
const token =
access_token: req.session.accessToken,
refresh_token: req.session.refreshToken,
scope: req.session.scope,
token_type: req.session.token_type,
expiry_date: req.session.expiry_date,
oAuth2Client.setCredentials(token);
const service = google.people( version: 'v1', oAuth2Client );
service.people.connections.list(
resourceName: 'people/me',
pageSize: 10,
personFields: 'names,emailAddresses,phoneNumbers',
, (err, res) =>
if (err) return resp.send(err);
const connections = res.data.connections;
if (connections)
console.log('Connections:');
connections.forEach((person) =>
if (person.names && person.names.length > 0)
resp.write(person.names);
else
resp.write('No display name found for connection.');
);
else
resp.write("No connections.");
res.end();
);
)
app.get('/auth/google',
passport.authenticate('google',
scope: ['profile', 'email', 'https://www.googleapis.com/auth/contacts'],
accessType: 'offline',
prompt: 'consent',
));
app.get('/auth/google/callback',
passport.authenticate('google', failureRedirect: '/login' ),
function (req, res)
res.redirect('/success');
);
app.listen(3000, () => console.log("Server is up and running on port 3000."));
我检查了几乎所有类似的 Stack Overflow 答案和 GitHub 问题。似乎什么都没有解决。
【问题讨论】:
可能是您正在使用异步创建 oAuth2Client 并且在使用 oAuth2Client 之前您没有访问 redirect_url? @Aerials 身份验证流程完全正常,我正在被重定向。 Cookie 也已设置,我还可以通过单独的 GET 请求使用 cookie 中设置的 access_token 获取联系人。 google.people() 出了点问题 您发布了您的 clientID 和 clientSecret,您可能需要更改它们。我建议删除与您的问题和代码无关的任何内容,并将其分解为 minimal-reproducible-example 这会有所帮助。 @Aerials 感谢您指出,我错过了从 passport.js 文件中删除的内容。而且我只包含了最少的代码来重现该问题。 尝试使用GoogleAuth.fromJSON()
,如Google Auth Library 中的“从环境变量加载凭据”部分所述。无论如何,我在那个库中找不到方法oAuth2Client.setCredentials(token)
。
【参考方案1】:
传递给 google.people 的第二个参数的名称是 auth
。
在 javascript 中,您可以将 auth: auth
写成简单的 auth
。在google提供的例子中,变量名与字段名相同,所以直接提供为auth
const service = google.people( version: 'v1', auth );
但是您的变量名称与字段名称不同。所以更改名称或将这一行替换为
const service = google.people( version: 'v1', auth: oAuth2Client );
它期望 auth
作为第二个属性,但它接收到一个具有名称的属性
oAuth2Client
这就是它不起作用的原因。
【讨论】:
你能指出使用的库的官方文档吗? 没有特别提到这一点,但我想通了global and service level auth部分中的这个 google-api-nodejs-client repo 自述文件以上是关于Google People API:请求具有无效的身份验证凭据 - 未设置授权承载标头的主要内容,如果未能解决你的问题,请参考以下文章
Google People API - 生日 - GET 请求中不返回日期对象
当我请求 google people api 时没有最后修改的时间戳
有啥方法可以从 google contact api v3 检索 account_id 以向 google people api 发出获取请求?