在 IoT-Core 上检索和编辑设备配置时出现身份验证错误
Authentication Error when Retrieving and Editing Device Configuration on IoT-Core
我正在尝试使用后端 nodeJS 服务器访问(和编辑)IoT-Core 上的设备配置,参考此 API docs
但是,我不断收到错误消息:
code 401 with error message "message": "Request had invalid authentication credentials. Expected OAuth 2 access token, login cookie or other valid authentication credential. See https://developers.google.com/identity/sign-in/web/devconsole-project.",
"status": "UNAUTHENTICATED".
我从 Google IAM
创建了一个服务帐户和一个密钥,并赋予它 Cloud IoT Device Controller 权限,它可以更新设备配置但不能创建或删除。随后,我将其更改为 Cloud IoT Admin 甚至 Project Editor permissions
,但仍然看到相同的错误消息。我是不是把钥匙弄错了,还是没有做我应该做的其他事情?
下面的代码是我调用请求的方式
function createJwt (projectId, privateKeyFile, algorithm) {
// Create a JWT to authenticate this device. The device will be disconnected
// after the token expires, and will have to reconnect with a new token. The
// audience field should always be set to the GCP project ID.
const token = {
'iat': parseInt(Date.now() / 1000),
'exp': parseInt(Date.now() / 1000) + 20 * 60, // 20 minutes
'aud': projectId
};
const privateKey = fs.readFileSync(privateKeyFile);
return jwt.sign(token, privateKey, { algorithm: algorithm });
}
app.get('/', function(req, res){
let authToken = createJwt('test-project', './keys/device-config.pem', 'RS256');
const options = {
url: 'https://cloudiot.googleapis.com/v1/projects/test-project/locations/us-central1/registries/dev-registry/devices/test-device',
headers: {
'authorization': 'Bearer ' + authToken,
'content-type': 'application/json',
'cache-control': 'no-cache'
},
json: true
}
request.get(options, function(error, response){
if(error) res.json(error);
else res.json(response);
})
});
请确认一下,当您创建 SSL 密钥对时,以及当您向 Cloud IoT Core 注册表注册设备时,您是否将创建的密钥类型与您注册时使用的单选按钮相匹配?
还要确认一下,您将 Google 根证书放在设备上与私钥相同的目录中:./keys/device-config.pem
?如果没有,您可以通过以下方式获取它:wget https://pki.google.com/roots.pem
.
对于与 IoT-Core 交互的后端服务器,身份验证方法与设备 MQTT 或 HTTP 连接不同。参考:https://cloud.google.com/iot/docs/samples/device-manager-samples#get_a_device
我能够使用以下代码检索和更新设备配置
function getClient (serviceAccountJson, cb) {
const serviceAccount = JSON.parse(fs.readFileSync(serviceAccountJson));
const jwtAccess = new google.auth.JWT();
jwtAccess.fromJSON(serviceAccount);
// Note that if you require additional scopes, they should be specified as a
// string, separated by spaces.
jwtAccess.scopes = 'https://www.googleapis.com/auth/cloud-platform';
// Set the default authentication to the above JWT access.
google.options({ auth: jwtAccess });
const DISCOVERY_API = 'https://cloudiot.googleapis.com/$discovery/rest';
const API_VERSION = 'v1';
const discoveryUrl = `${DISCOVERY_API}?version=${API_VERSION}`;
google.discoverAPI(discoveryUrl, {}, (err, client) => {
if (err) {
console.log('Error during API discovery', err);
return undefined;
}
cb(client);
});
}
function getDevice (client, deviceId, registryId, projectId, cloudRegion) {
const parentName = `projects/${process.env.GCP_PROJECT_ID}/locations/${cloudRegion}`;
const registryName = `${parentName}/registries/${registryId}`;
const request = {
name: `${registryName}/devices/${deviceId}`
};
const promise = new Promise(function(resolve, reject){
client.projects.locations.registries.devices.get(request, (err, data) => {
if (err) {
console.log('Could not find device:', deviceId);
console.log(err);
reject(err);
} else {
console.log(data.config.binaryData);
resolve(data);
}
});
});
return promise;
}
app.get('/', function(req, res){
const cb = function(client){
getDevice(client, 'test-device', 'dev-registry', process.env.GCP_PROJECT_ID, 'us-central1')
.then(function(response){
let decoded = new Buffer(response.config.binaryData, 'base64').toString();
res.json(decoded);
})
.catch(function(error){
res.json(error);
})
}
getClient(serviceAccountJson, cb);
});
我认为最好使用 NodeJS 的客户端库来完成您想要做的事情。
首先,检索一个 API 客户端对象作为 done in the sample。这将获取您使用的服务帐户凭据,并将针对 Google API 核心服务器进行身份验证。
在调用 cb(client);
的引用代码中,您将拥有客户端对象并准备好更新您的设备。添加示例中的导入和 API 常量,并将具有客户端对象的代码替换为以下代码,您应该设置。
使用一些字符串作为您的设备标识符:
const projectId = 'my-project';
const cloudRegion = 'us-central1';
const registryId = 'my-registry';
const deviceId = 'my-device;
const config = '{fan: 800}';
接下来,形成您的设备字符串:
const deviceId = `projects/${projectId}/locations/${cloudRegion}/registries/${registryId}/devices/${deviceId}`;
const binaryData = Buffer.from(config).toString('base64');
现在你形成你的请求对象并执行:
const request = {
name: `${registryName}`,
versionToUpdate: 0,
binaryData: binaryData
};
console.log(request);
client.projects.locations.registries.devices
.modifyCloudToDeviceConfig(
request,
(err, data) => {
if (err) {
console.log('Could not update config:', deviceId);
console.log('Message: ', err);
} else {
console.log('Success :', data);
}
});
您的配置已更新。如果您的设备订阅了 MQTT 上的配置主题,它将收到最新的配置,否则,您可以从您的设备使用 HTTP 轮询配置。
我正在尝试使用后端 nodeJS 服务器访问(和编辑)IoT-Core 上的设备配置,参考此 API docs
但是,我不断收到错误消息:
code 401 with error message "message": "Request had invalid authentication credentials. Expected OAuth 2 access token, login cookie or other valid authentication credential. See https://developers.google.com/identity/sign-in/web/devconsole-project.", "status": "UNAUTHENTICATED".
我从 Google IAM
创建了一个服务帐户和一个密钥,并赋予它 Cloud IoT Device Controller 权限,它可以更新设备配置但不能创建或删除。随后,我将其更改为 Cloud IoT Admin 甚至 Project Editor permissions
,但仍然看到相同的错误消息。我是不是把钥匙弄错了,还是没有做我应该做的其他事情?
下面的代码是我调用请求的方式
function createJwt (projectId, privateKeyFile, algorithm) {
// Create a JWT to authenticate this device. The device will be disconnected
// after the token expires, and will have to reconnect with a new token. The
// audience field should always be set to the GCP project ID.
const token = {
'iat': parseInt(Date.now() / 1000),
'exp': parseInt(Date.now() / 1000) + 20 * 60, // 20 minutes
'aud': projectId
};
const privateKey = fs.readFileSync(privateKeyFile);
return jwt.sign(token, privateKey, { algorithm: algorithm });
}
app.get('/', function(req, res){
let authToken = createJwt('test-project', './keys/device-config.pem', 'RS256');
const options = {
url: 'https://cloudiot.googleapis.com/v1/projects/test-project/locations/us-central1/registries/dev-registry/devices/test-device',
headers: {
'authorization': 'Bearer ' + authToken,
'content-type': 'application/json',
'cache-control': 'no-cache'
},
json: true
}
request.get(options, function(error, response){
if(error) res.json(error);
else res.json(response);
})
});
请确认一下,当您创建 SSL 密钥对时,以及当您向 Cloud IoT Core 注册表注册设备时,您是否将创建的密钥类型与您注册时使用的单选按钮相匹配?
还要确认一下,您将 Google 根证书放在设备上与私钥相同的目录中:./keys/device-config.pem
?如果没有,您可以通过以下方式获取它:wget https://pki.google.com/roots.pem
.
对于与 IoT-Core 交互的后端服务器,身份验证方法与设备 MQTT 或 HTTP 连接不同。参考:https://cloud.google.com/iot/docs/samples/device-manager-samples#get_a_device
我能够使用以下代码检索和更新设备配置
function getClient (serviceAccountJson, cb) {
const serviceAccount = JSON.parse(fs.readFileSync(serviceAccountJson));
const jwtAccess = new google.auth.JWT();
jwtAccess.fromJSON(serviceAccount);
// Note that if you require additional scopes, they should be specified as a
// string, separated by spaces.
jwtAccess.scopes = 'https://www.googleapis.com/auth/cloud-platform';
// Set the default authentication to the above JWT access.
google.options({ auth: jwtAccess });
const DISCOVERY_API = 'https://cloudiot.googleapis.com/$discovery/rest';
const API_VERSION = 'v1';
const discoveryUrl = `${DISCOVERY_API}?version=${API_VERSION}`;
google.discoverAPI(discoveryUrl, {}, (err, client) => {
if (err) {
console.log('Error during API discovery', err);
return undefined;
}
cb(client);
});
}
function getDevice (client, deviceId, registryId, projectId, cloudRegion) {
const parentName = `projects/${process.env.GCP_PROJECT_ID}/locations/${cloudRegion}`;
const registryName = `${parentName}/registries/${registryId}`;
const request = {
name: `${registryName}/devices/${deviceId}`
};
const promise = new Promise(function(resolve, reject){
client.projects.locations.registries.devices.get(request, (err, data) => {
if (err) {
console.log('Could not find device:', deviceId);
console.log(err);
reject(err);
} else {
console.log(data.config.binaryData);
resolve(data);
}
});
});
return promise;
}
app.get('/', function(req, res){
const cb = function(client){
getDevice(client, 'test-device', 'dev-registry', process.env.GCP_PROJECT_ID, 'us-central1')
.then(function(response){
let decoded = new Buffer(response.config.binaryData, 'base64').toString();
res.json(decoded);
})
.catch(function(error){
res.json(error);
})
}
getClient(serviceAccountJson, cb);
});
我认为最好使用 NodeJS 的客户端库来完成您想要做的事情。
首先,检索一个 API 客户端对象作为 done in the sample。这将获取您使用的服务帐户凭据,并将针对 Google API 核心服务器进行身份验证。
在调用 cb(client);
的引用代码中,您将拥有客户端对象并准备好更新您的设备。添加示例中的导入和 API 常量,并将具有客户端对象的代码替换为以下代码,您应该设置。
使用一些字符串作为您的设备标识符:
const projectId = 'my-project';
const cloudRegion = 'us-central1';
const registryId = 'my-registry';
const deviceId = 'my-device;
const config = '{fan: 800}';
接下来,形成您的设备字符串:
const deviceId = `projects/${projectId}/locations/${cloudRegion}/registries/${registryId}/devices/${deviceId}`;
const binaryData = Buffer.from(config).toString('base64');
现在你形成你的请求对象并执行:
const request = {
name: `${registryName}`,
versionToUpdate: 0,
binaryData: binaryData
};
console.log(request);
client.projects.locations.registries.devices
.modifyCloudToDeviceConfig(
request,
(err, data) => {
if (err) {
console.log('Could not update config:', deviceId);
console.log('Message: ', err);
} else {
console.log('Success :', data);
}
});
您的配置已更新。如果您的设备订阅了 MQTT 上的配置主题,它将收到最新的配置,否则,您可以从您的设备使用 HTTP 轮询配置。