我正在尝试以编程方式访问我的Google Play开发者帐户的Google云存储分区,以获取应用程序的统计信息。即使我已将我的服务帐户添加到播放控制台并为其授予了管理员权限,我仍收到身份验证错误。
'use strict'
const { google } = require('googleapis')
const {Storage} = require('@google-cloud/storage');
const key = require('../Gcloud-service-account.json')
const scopes = 'https://www.googleapis.com/auth/devstorage.read_only'
const jwt = new google.auth.JWT(key.client_email, null, key.private_key, scopes)
process.env.GOOGLE_APPLICATION_CREDENTIALS = '../Gcloud-service-account.json';
jwt.authorize((err, response) => {
const authCloudExplicit = async () => {
// [START auth_cloud_explicit]
// Imports the Google Cloud client library.
const projectId = 'gplay-stats-nodejs'
const keyFilename = '../Gcloud-service-account.json'
const storage = new Storage({projectId, keyFilename});
console.log('outside try')
// Makes an authenticated API request.
try {
const [buckets] = await storage.getBuckets();
console.log('inside try')
buckets.forEach(bucket => {
console.log(bucket.name);
});
} catch (err) {
console.error('ERROR:', err);
}
// [END auth_cloud_explicit]
};
authCloudExplicit();
//Reading data
async function downloadFile() {
// [START storage_download_file]
// Imports the Google Cloud client library
// Creates a client
const storage = new Storage();
/**
* TODO(developer): Uncomment the following lines before running the sample.
*/
const bucketName = 'pubsite__rev_05768497717432290806/stats/installs';
const srcFilename = 'installs_package-id-of-my-app_201901_app_version.csv';
const destFilename = '../download';
const options = {
destination: destFilename,
};
// Downloads the file
await storage
.bucket(bucketName)
.file(srcFilename)
.download(options);
console.log(
`gs://${bucketName}/${srcFilename} downloaded to ${destFilename}.`
);
}
downloadFile();
(err, result) => {
console.log(err, result)
}
})
//Here is my service account json
{
"type": "service_account",
"project_id": "",
"private_key_id": "",
"private_key": "",
"client_email": "",
"client_id": "",
"auth_uri": "https://accounts.google.com/o/oauth2/auth",
"token_uri": "https://oauth2.googleapis.com/token",
"auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
"client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/service-account-email"
}
删除了一些机密字段。
我收到此错误:
code: 403,
errors: [
{
domain: 'global',
reason: 'forbidden',
message: 'service-account-email' +
'does not have storage.buckets.list access to project ' +
'2763836207.'
}
],
response: PassThrough {
_readableState: ReadableState {
objectMode: false,
highWaterMark: 16384,
buffer: BufferList { head: null, tail: null, length: 0 },
length: 0,
pipes: null,
pipesCount: 0,
flowing: true,
ended: true,
endEmitted: true,
reading: false,
sync: false,
needReadable: false,
emittedReadable: false,
readableListening: false,
resumeScheduled: false,
paused: false,
emitClose: true,
autoDestroy: false,
destroyed: false,
defaultEncoding: 'utf8',
awaitDrain: 0,
readingMore: false,
decoder: null,
encoding: null
},
readable: false,
_events: [Object: null prototype] {
prefinish: [Function: prefinish],
error: [Array],
data: [Function],
end: [Function]
},
_eventsCount: 4,
_maxListeners: undefined,
_writableState: WritableState {
objectMode: false,
highWaterMark: 16384,
finalCalled: false,
needDrain: false,
ending: true,
ended: true,
finished: true,
destroyed: false,
decodeStrings: true,
defaultEncoding: 'utf8',
length: 0,
writing: false,
corked: 0,
sync: false,
bufferProcessing: false,
onwrite: [Function: bound onwrite],
writecb: null,
writelen: 0,
bufferedRequest: null,
lastBufferedRequest: null,
pendingcb: 0,
prefinished: true,
errorEmitted: false,
emitClose: true,
autoDestroy: false,
bufferedRequestCount: 0,
corkedRequestsFree: [Object]
},
writable: false,
allowHalfOpen: true,
_transformState: {
afterTransform: [Function: bound afterTransform],
needTransform: false,
transforming: false,
writecb: null,
writechunk: null,
writeencoding: 'buffer'
},
statusCode: 403,
statusMessage: 'Forbidden',
request: {
headers: [Object],
href: 'https://www.googleapis.com/storage/v1/b?project=gplay-stats-nodejs'
},
body: '{\n "error": {\n "errors": [\n {\n "domain": "global",\n ' +
'"reason": "forbidden",\n "message": ' +
'"service-account-email does ' +
'not have storage.buckets.list access to project 2763836207."\n }\n ' +
'],\n "code": 403,\n "message": ' +
'"service-account-email does ' +
'not have storage.buckets.list access to project 2763836207."\n }\n}\n',
headers: {
'alt-svc': 'quic=":443"; ma=2592000; v="46,43,39"',
'cache-control': 'private, max-age=0',
connection: 'close',
'content-length': '400',
'content-type': 'application/json; charset=UTF-8',
date: 'Sun, 04 Aug 2019 21:46:39 GMT',
expires: 'Sun, 04 Aug 2019 21:46:39 GMT',
server: 'UploadServer',
vary: 'Origin, X-Origin',
'x-guploader-uploadid': 'AEnB2UqCDuQdbWsAmyTty5rImnOYxLB71xh5hf7-4boSY9c5d7cCZly5mQJsbJY57emgn9jyGDVKtlDM4jeUG07IJKl7I3RpxQ'
},
toJSON: [Function: toJSON]
},
message: 'service-account-email ' +
'does not have storage.buckets.list access to project ' +
'2763836207.'
}
答案 0 :(得分:0)
您的服务帐户的作用是什么?它必须只有存储对象查看器,不是吗? 该角色允许您的服务帐户查看存储桶中的对象。但是在这里,您还需要在这一行中列出存储桶
const [buckets] = await storage.getBuckets();
顺便说一句,您的服务帐户还需要角色storageAdmin或projectViewer中包含的storage.buckets.list
权限。就个人而言,我更喜欢并推荐projectViewer,因为即使该角色可以查看项目的所有资源,该角色也无法创建/删除存储桶。
最好的解决方案是创建一个自定义角色,只有获得正确的权限。使用代码并不总是一个好的解决方案,因为库有时会执行您不处理和/或不希望执行的调用。在Python中就是这种情况,也许在节点中也是如此。