Error: User credentials required in Google Cloud Print API
Error: User credentials required in Google Cloud Print API
我正在尝试使用 Google 云打印 (GCP) API,但无法正常工作。
也许我对工作流程理解不佳,因为这是我第一次使用 google api,请帮助我了解如何使其工作。
初步考虑:
- 我试图在 reactJS 中实现它,但它无动于衷,因为使 GCP 工作的逻辑独立于技术。那你也可以帮我了解一下工作流程。
我到底想要什么:
为了进行第一次测试,我希望获得有关我的打印机的所有信息。
我做了什么:
- 我在以下位置创建了一个项目:https://console.developers.google.com
- 在创建的项目中,我创建了一个凭证:
- 创建凭据 -> OAuth 客户端 ID
然后我选择了应用程序类型:Web,并且还配置了源限制和重定向到我的本地主机。
我在 https://www.google.com/cloudprint 中手动添加了我的打印机,我进行了打印 PDF 的测试并且没问题。
我在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)
获取打印机信息的动作或函数:
解释:
我正在传递参数 printerid
以获取有关该打印机的信息。
在授权中,我使用 OAuth ...
因为在文档中说(第二段):https://developers.google.com/cloud-print/docs/appInterfaces
下两个headers我写的是因为我尝试了解决方案:
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 的代码示例很少。
解法:
描述的步骤是好的,直到第四步我使用外部组件 react-google-login
来尝试获取访问令牌,而不是我使用 googleapis
模块:Link Github googleapis
同时为了避免 CORS 问题(并且不使用 CORS chrome 插件)我将请求写入服务器端的 Google API。(NODEJS)
当我尝试生成弹出窗口以授予打印机权限时,我在前端也遇到了问题(关于 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 token
、refresh token
和expiration 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
,它并不明显,我花了一天时间才搞清楚。
我正在尝试使用 Google 云打印 (GCP) API,但无法正常工作。 也许我对工作流程理解不佳,因为这是我第一次使用 google api,请帮助我了解如何使其工作。
初步考虑:
- 我试图在 reactJS 中实现它,但它无动于衷,因为使 GCP 工作的逻辑独立于技术。那你也可以帮我了解一下工作流程。
我到底想要什么:
为了进行第一次测试,我希望获得有关我的打印机的所有信息。
我做了什么:
- 我在以下位置创建了一个项目:https://console.developers.google.com
- 在创建的项目中,我创建了一个凭证:
- 创建凭据 -> OAuth 客户端 ID
然后我选择了应用程序类型:Web,并且还配置了源限制和重定向到我的本地主机。
我在 https://www.google.com/cloudprint 中手动添加了我的打印机,我进行了打印 PDF 的测试并且没问题。
我在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)
获取打印机信息的动作或函数:
解释:
我正在传递参数
printerid
以获取有关该打印机的信息。在授权中,我使用
OAuth ...
因为在文档中说(第二段):https://developers.google.com/cloud-print/docs/appInterfaces下两个headers我写的是因为我尝试了解决方案:
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 的代码示例很少。
解法:
描述的步骤是好的,直到第四步我使用外部组件
react-google-login
来尝试获取访问令牌,而不是我使用googleapis
模块:Link Github googleapis同时为了避免 CORS 问题(并且不使用 CORS chrome 插件)我将请求写入服务器端的 Google API。(NODEJS)
当我尝试生成弹出窗口以授予打印机权限时,我在前端也遇到了问题(关于 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 token
、refresh token
和expiration 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
,它并不明显,我花了一天时间才搞清楚。