我写了一个关于谷歌api使用的例子。 Google NodeJS Client library。我已遵循指令集access_type : 'offline'
,但对象返回不包含refresh_token
。
我的代码:
var http = require('http');
var express = require('express');
var Session = require('express-session');
var google = require('googleapis');
var plus = google.plus('v1');
var OAuth2 = google.auth.OAuth2;
const ClientId = "251872680446-rvkcvm5mjn1ps32iabf4i2611hcg086e.apps.googleusercontent.com";
const ClientSecret = "F1qG9fFS-QwcrEfZbT8VmUnx";
const RedirectionUrl = "http://localhost:8081/oauthCallback";
var app = express();
app.use(Session({
secret: 'raysources-secret-19890913007',
resave: true,
saveUninitialized: true
}));
function getOAuthClient () {
return new OAuth2(ClientId , ClientSecret, RedirectionUrl);
}
function getAuthUrl () {
var oauth2Client = getOAuthClient();
// generate a url that asks permissions for Google+ and Google Calendar scopes
var scopes = [
'https://www.googleapis.com/auth/plus.me'
];
var url = oauth2Client.generateAuthUrl({
access_type: 'offline',
scope: scopes // If you only need one scope you can pass it as string
});
return url;
}
app.use("/oauthCallback", function (req, res) {
var oauth2Client = getOAuthClient();
var session = req.session;
var code = req.query.code;
oauth2Client.getToken(code, function(err, tokens) {
console.log("tokens : ", tokens);
// Now tokens contains an access_token and an optional refresh_token. Save them.
if(!err) {
oauth2Client.setCredentials(tokens);
session["tokens"]=tokens;
res.send(`
<html>
<body>
<h3>Login successful!!</h3>
<a href="/details">Go to details page</a>
<body>
<html>
`);
}
else{
res.send(`
<html>
<body>
<h3>Login failed!!</h3>
</body>
</html>
`);
}
});
});
app.use("/details", function (req, res) {
var oauth2Client = getOAuthClient();
oauth2Client.setCredentials(req.session["tokens"]);
var p = new Promise(function (resolve, reject) {
plus.people.get({ userId: 'me', auth: oauth2Client }, function(err, response) {
console.log("response : " , response);
resolve(response || err);
});
}).then(function (data) {
res.send(`<html><body>
<img src=${data.image.url} />
<h3>Hello ${data.displayName}</h3>
</body>
</html>
`);
})
});
app.use("/", function (req, res) {
var url = getAuthUrl();
res.send(`
<html>
<body>
<h1>Authentication using google oAuth</h1>
<a href=${url}>Login</a>
</body>
</html>
`)
});
var port = 8081;
var server = http.createServer(app);
server.listen(port);
server.on('listening', function () {
console.log(`listening to ${port}`);
});
答案 0 :(得分:3)
刷新令牌仅在用户首次批准您指定的范围后登录到您的应用程序时发送。
编辑08/2018 :使用approval_prompt:'force'
不再有效,您需要使用prompt:'consent'
(查看@ Alexander的答案)
如果您想在每次用户登录时获取刷新令牌(即使用户之前已经登录并批准了作用域),您必须在prompt:'consent'
配置中指定Oauth2Client
:
var url = oauth2Client.generateAuthUrl({
access_type: 'offline',
scope: scopes,
prompt : 'consent'
});
请注意,每次他/她点击您的链接进行身份验证时,都需要用户接受指定的范围:
您也可以在account permission settings中手动禁用该应用程序,这将撤销该应用程序,用户必须再次接受该范围,以便在您下次验证时触发refresh_token
:
仅供参考,如果您需要离线使用access_token
,则必须存储refresh_token
服务器端,并在从Google API收到状态401时使用存储的refresh_token
刷新access_token 。因此,如果您按照应有的方式存储refresh_token
,则实际上无需使用prompt:'consent'
并强制用户在每次连接到您的应用程序时批准范围。
答案 1 :(得分:1)
根据documentation,refresh_token仅在第一次授权时返回。
您可以手动删除以下权限:https://myaccount.google.com/permissions
您还可以通过在授权URL中传递&prompt = consent来强制用户再次查看consent屏幕,只需添加以下参数即可:
var url = oauth2Client.generateAuthUrl({
access_type: 'offline',
scope: scopes,
prompt: 'consent'
});
对我来说效果很好:)
答案 2 :(得分:0)
在某些情况下(主要是Web客户端),刷新令牌仅在用户首次通过身份验证时发送。
如果您转到apps connected to your account,请移除相关应用。然后尝试再次验证。检查并且现在应该有一个刷新令牌。