Error: User credentials required in Google Cloud Print API

Error: User credentials required in Google Cloud Print API

我正在尝试使用 Google 云打印 (GCP) API,但无法正常工作。 也许我对工作流程理解不佳,因为这是我第一次使用 google api,请帮助我了解如何使其工作。

初步考虑:

我到底想要什么:

为了进行第一次测试,我希望获得有关我的打印机的所有信息。

我做了什么:

  1. 我在以下位置创建了一个项目:https://console.developers.google.com
  2. 在创建的项目中,我创建了一个凭证:
    • 创建凭据 -> OAuth 客户端 ID

然后我选择了应用程序类型:Web,并且还配置了源限制和重定向到我的本地主机。

  1. 我在 https://www.google.com/cloudprint 中手动添加了我的打印机,我进行了打印 PDF 的测试并且没问题。

  2. 我在reactJS中创建了一个项目来获取我添加的打印机的信息。

分量:

解释:

代码:

import React, { Component } from 'react'
import GoogleLogin from 'react-google-login';
import { connect } from 'react-redux'

import { getPrinters } from '../actions/settings'

class Setting extends Component {

  responseGoogle(response) {
    const accessToken = response.accessToken
    localStorage.setItem('googleToken', accessToken)
  }

  render() {
    return (
      <div>
        <GoogleLogin
          clientId="CLIENT_ID_REMOVED_INTENTIONALLY.apps.googleusercontent.com"
          buttonText="Login"
          onSuccess={this.responseGoogle}
          onFailure={this.responseGoogle}
        />
        <button
          onClick = {() => {
            this.props.getPrinters()
          }}
        >test printer</button>
      </div>
    )
  }

}

const mapStateToProps = state => {
  return {
    state: state
  }
}

const mapDispatchToProps = dispatch => {
  return {
    getPrinters() {
      dispatch(getPrinters())
    }
  }
}

export default connect(
  mapStateToProps,
  mapDispatchToProps
)(Setting)

获取打印机信息的动作或函数:

解释:

Google Cloud Print API: User credentials required

代码:

import axios from 'axios'

axios.defaults.headers.common['Authorization'] = 'OAuth ' +    localStorage.getItem('googleToken')
axios.defaults.headers.common['scope'] =   'https://www.googleapis.com/auth/cloudprint'
axios.defaults.headers.common['X-CloudPrint-Proxy'] = 'printingTest'

const getPrinters = () => {

  return () => {
    return axios.get('https://www.google.com/cloudprint/printer'
      , {
          params: {
            printeid: 'PRINTER_ID_REMOVED_INTENTIONALLY'
          }
        }
      )
      .then(response => {
        console.log('response of google cloud print')
        console.log(response)
      })
  }

}

export { getPrinters }

错误:

之前的所有解释之后,我得到了下一个错误:

User credentials required

Error 403

注:

我正在使用推荐的 CORS 插件:

因为最初,我有 cors 错误。

任何建议或推荐都会非常有用,谢谢。

我已经解决了我的问题,我关于 User Credential required 的主要问题是因为我使用了不正确的访问令牌,这是因为我错误地获取了访问令牌。

我将解释我的整个解决方案,因为这个 API 的代码示例很少。

解法:

  1. 描述的步骤是好的,直到第四步我使用外部组件 react-google-login 来尝试获取访问令牌,而不是我使用 googleapis 模块:Link Github googleapis

  2. 同时为了避免 CORS 问题(并且不使用 CORS chrome 插件)我将请求写入服务器端的 Google API。(NODEJS)

  3. 当我尝试生成弹出窗口以授予打印机权限时,我在前端也遇到了问题(关于 CORS 的问题),我的解决方案是使用这个非常简单的模块进行身份验证:Link Github oauth-open

总方案:

解释:

知道我有问题中描述的所有数据post(直到第三步)。

身份验证:

  • 下一步得到一个URL并用它来对用户进行身份验证。 正如我之前所说,我在前端使用模块 oauth-open 来生成弹出窗口,只有这个模块需要 URL。为了在后端获取 URL,我使用了端点 /googleurl,在这里我使用了模块 googleapis 的方法 generateAuthUrl 来生成 URL。

  • 在那之后,在前端,我得到了 authentication_code(返回模块 oauth-open),我将它发送到我的端点 /googletoken,在这里我使用模块googleapis的方法getToken处理authentication_code生成access tokenrefresh tokenexpiration date。最后将这些数据存入数据库

打印:

  • 对于打印,从前端开始,我将需要发送的数据发送到打印机。我使用了我的端点 /print

  • 在后端端点,我的逻辑是下一个:

从数据库中恢复token和过期日期,根据过期日期检查token是否过期,如果已经过期则获取另一个token并将旧的access token替换为新的,同时替换使用新的 expiration date,要获取此新数据,只需调用模块 googleapis 的方法 refreshAccessToken。注意:刷新令牌永不过期。

更新访问令牌后,使用它通过 Google route(.../submit)

将数据发送到打印机

代码:

  • 后面所有代码只在1个文件里
  • 一些数据作为验证、静态变量、错误处理程序等已被删除以便更好地理解。

路由获得URL认证。

const express = require('express');
const google = require('googleapis');
const router = express.Router();

var OAuth2 = google.auth.OAuth2;
const redirect_url = 'http://localhost:3001/setting';  //Your redirect URL
var oauth2Client = new OAuth2(
  'CLIENT ID',      //Replace it with your client id
  'CLIEND SECRET',  //Replace it with your client secret
   redirect_url
);

var url = oauth2Client.generateAuthUrl({
    access_type: 'offline',
    scope: 'https://www.googleapis.com/auth/cloudprint'
});

router.get('/googleurl', (req, res) => {
    return res.status(200).send({
      result: { googleURLToken: url }
    });
 });

使用验证码获取令牌并将其保存在数据库中。

const Setting = require('../models/setting'); // My model(Mongoose)

router.post('/googletoken', (req, res) => {
    oauth2Client.getToken(req.body.code, function (err, tokens) {
      oauth2Client.credentials = tokens;
      // If refresh token exits save it
      // because the refresh token it returned only 1 time! IMPORTANT
      if (tokens.hasOwnProperty('refresh_token')) {

        let setting = new Setting();
        setting.refreshTokenGoogle = tokens.refresh_token;
        setting.expirationTokenGoogle = tokens.expiry_date;
        setting.tokenGoogle = tokens.access_token;

        setting.save()
          .then((settingCreated) => {
              return res.status(200).send({
                  message: 'OK'
              });
           })
      }
    });
});

打印

const axios = require('axios');
const moment = require('moment');

router.post('/print',async (req, res) => {

    const tickeProperties = {
      'version': '1.0',
      'print': {
        'vendor_ticket_item': [],
        'color': { 'type': 'STANDARD_MONOCHROME' },
        'copies': { 'copies': 1 }
      }
    };

    const accessToken = await getTokenGoogleUpdated();
    axios.get(
      'https://www.google.com/cloudprint/submit',
      {
        params: {
          printerid : printerID, // Replace by your printer ID
          title: 'title printer',
          ticket: tickeProperties,
          content : 'print this text of example!!!',
          contentType: 'text/plain'
        },
        headers: {
          'Authorization': 'Bearer ' + accessToken
        }
      }
    )
      .then(response => {
        return res.status(200).send({
          result: response.data
        });
      })
  }
);

async function getTokenGoogleUpdated() {

  return await Setting.find({})
    .then(async setting => {
      const refreshTokenGoogle = setting[0].refreshTokenGoogle;
      const expirationTokenGoogle = setting[0].expirationTokenGoogle;
      const tokenGoogle = setting[0].tokenGoogle;

      const dateToday = new Date();
      // 1 minute forward to avoid exact time
      const dateTodayPlus1Minute = moment(dateToday).add(1, 'm').toDate();
      const dateExpiration = new Date(expirationTokenGoogle);

      // Case date expiration, get new token
      if (dateExpiration < dateTodayPlus1Minute) {
        console.log('Updating access token');
        oauth2Client.credentials['refresh_token'] = refreshTokenGoogle;
        return await oauth2Client.refreshAccessToken( async function(err, tokens) {
          // Save new token and new expiration
          setting[0].expirationTokenGoogle = tokens.expiry_date;
          setting[0].tokenGoogle = tokens.access_token;

          await setting[0].save();

          return tokens.access_token;
        });

      } else {
        console.log('Using old access token');
        return tokenGoogle;
      }

    })
    .catch(err => {
      console.log(err);
    });

}

如果你想使用Google云打印,我希望它能帮助你不要像我一样浪费很多时间。

重要的部分有一个范围 https://www.googleapis.com/auth/cloudprint,它并不明显,我花了一天时间才搞清楚。