错误:Google Cloud Print API需要用户凭证

Pab*_*les 0 google-api google-cloud-print google-oauth reactjs

我正在尝试使用Google Cloud Print(GCP)API,但无法使其正常运行。也许我对工作流程的理解不正确,因为这是我第一次使用Google API,请帮助我了解如何使其工作。

初步考虑:

  • 我正在尝试在reactJS中实现它,但这并不重要,因为使GCP起作用的逻辑与技术无关。然后,您也可以帮助我了解工作流程。

我到底想要什么:

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

我做了什么:

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

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

  1. 我在https://www.google.com/cloudprint中手动添加了打印机,并进行了打印PDF的测试,一切正常。

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

零件:

说明:

  • 我正在使用一个组件react-google-login来轻松获取用户accessToken:https : //github.com/anthonyjgrove/react-google-login

  • 该组件仅获取访问令牌并将其保存在localStorage中的变量中googleToken,它绘制一个按钮以调用函数以获取有关打印机的信息。

码:

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)
Run Code Online (Sandbox Code Playgroud)

获取信息打印机的动作或功能:

说明:

Google Cloud Print API:需要用户凭证

需要Google Cloud Print用户凭证

码:

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 }
Run Code Online (Sandbox Code Playgroud)

错误:

毕竟在我解释完之后,我得到了下一个错误:

需要用户凭证

错误403

注意:

根据以下建议,我正在使用CORS插件:

Chrome扩展程序可进行静音打印?

因为最初,我有cors错误。

任何建议或建议都将非常有用,谢谢。

Pab*_*les 5

我已经解决了我的问题,我的主要问题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

总体方案:

在此处输入图片说明

说明:

知道我已经在问题帖中描述了所有数据(直到第三步)。

认证方式:

  • 获取URL并将其用于用户的下一步可以进行身份​​验证。就像我之前说过的,我oauth-open在前端使用模块来生成弹出窗口,只有该模块需要URL。为了在后端获取URL,我使用了endpoint /googleurl,在这里我使用generateAuthUrl了模块的方法googleapis来生成URL。

  • 之后,在前台,我得到了authentication_code(返回的模块oauth-open),我把它给我的终点/googletoken,在这里我处理authentication_code生成access tokenrefresh tokenexpiration date用该方法getToken的模块googleapis。最后,这些数据存储在数据库中。

打印:

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

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

从数据库中恢复令牌和到期日期,并用到期日期检查令牌是否已过期,如果令牌已过期,则获取另一个令牌,并用access token新令牌替换旧令牌,也用新令牌替换expiration date,以仅获取此新数据是refreshAccessToken对模块方法的必要调用googleapis。注意:刷新令牌永不过期。

更新访问令牌后,使用它通过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 }
    });
 });
Run Code Online (Sandbox Code Playgroud)

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

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'
              });
           })
      }
    });
});
Run Code Online (Sandbox Code Playgroud)

打印

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

}
Run Code Online (Sandbox Code Playgroud)

希望它对您有帮助,如果您不想使用Google Cloud Print浪费很多时间。