在IoT-Core上检索和编辑设备配置时的身份验证错误

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了在IoT-Core上检索和编辑设备配置时的身份验证错误相关的知识,希望对你有一定的参考价值。

我正在尝试使用后端nodeJS服务器来访问(和编辑)IoT-Core上的设备配置,参考API文档:https://cloud.google.com/iot/docs/reference/rest/v1/projects.locations.registries.devices/get

但是,我不断收到错误代码401并显示错误消息“message”:“请求具有无效的身份验证凭据。预期的OAuth 2访问令牌,登录cookie或其他有效的身份验证凭据。请参阅https://developers.google.com/identity/sign-in/web/devconsole-project。”,“status”:“UNAUTHENTICATED”。

我从Google IAM创建了一个服务帐户和一个密钥,并为其提供了Cloud IoT Device Controller权限,该权限可以更新设备配置但不能创建或删除。随后,我将其更改为Cloud IoT Admin甚至是Project Editor权限,但仍然看到了相同的错误消息。我得到的钥匙都错了,还是没做其他我应该做的事情?

下面的代码是我如何调用请求

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);
    })

});
答案

对于与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 Core服务器进行身份验证。

在引用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轮询配置。

另一答案

只是要确认,当您创建SSL密钥对时,以及使用Cloud IoT Core注册表注册设备时,您是否匹配使用您注册的单选按钮创建的密钥类型?

另外要确认,您将设备上的Google根证书放在与私钥相同的目录中:./keys/device-config.pem?如果没有,你可以用:wget https://pki.google.com/roots.pem获取它。

以上是关于在IoT-Core上检索和编辑设备配置时的身份验证错误的主要内容,如果未能解决你的问题,请参考以下文章

在设备上运行但适用于模拟器时的 iOS 配置文件问题

SCCM的证书配置PKI

Node Express - 身份验证令牌的存储和检索

因为你组织的安全策略阻止未经身份验证的来宾

Azure AD:50155 设备身份验证失败

使用颤振和 Firebase 身份验证在设备上持久化用户