请求对Google联系人的身份验证范围不足

问题描述 投票:0回答:1
/* eslint-disable no-underscore-dangle */
/* eslint-disable better-mutation/no-mutating-methods */

import React, { Component } from 'react'
import PropTypes from 'prop-types'
import xml from 'xml-js'

import Icon from './icon'
import ButtonContent from './button-content'

import { extractTitleFromEntry, extractEmailFromEntry, extractPhoneNumberFromEntry } from './utils'

const SCOPE = 'https://www.googleapis.com/auth/spreadsheets.readonly'
const MAX_RESULTS = '999' // TODO Make this parametable or paginate
class GoogleContacts extends Component {
  constructor(props) {
    super(props)
    this.signIn = this.signIn.bind(this)
    this.handleImportContacts = this.handleImportContacts.bind(this)
    this.handleParseContacts = this.handleParseContacts.bind(this)
    this.state = {
      hovered: false,
      active: false
    }
  }

  componentDidMount() {
    const { jsSrc } = this.props
    ;((d, s, id, cb) => {
      const element = d.getElementsByTagName(s)[0]
      const fjs = element
      let js = element
      js = d.createElement(s)
      js.id = id
      js.src = jsSrc
      if (fjs && fjs.parentNode) {
        fjs.parentNode.insertBefore(js, fjs)
      } else {
        d.head.appendChild(js)
      }
      js.onload = cb
    })(document, 'script', 'google-contacts')
  }

  handleImportContacts(res) {
    const { onFailure } = this.props

    if (res) {
      const authResponse = res.getAuthResponse();
      window.gapi.load('client', () => {
        window.gapi.client
          .request({
            path: '/m8/feeds/contacts/full',
            params: { 'max-results': MAX_RESULTS},
            headers: {
              'GData-Version': '3.0',
              Authorization: `Bearer ${authResponse.access_token}`
            }
          })
          .then(response => this.handleParseContacts(response), err => onFailure(err))
      })
    }
  }

  handleParseContacts(response) {
    const { onSuccess } = this.props

    // Now let's parse the XML...
    const options = { ignoreDeclaration: true, ignoreComment: true, compact: true }
    const parsed = xml.xml2js(response.body, options)

    // Iterate over each contact.
    const results = []

    Object.keys(parsed.feed.entry).forEach(key => {
      if (
        parsed.feed.entry[key] &&
        parsed.feed.entry[key]['gd:email'] &&
        parsed.feed.entry[key]['gd:email']._attributes &&
        parsed.feed.entry[key]['gd:email']._attributes.address
      ) {
        results.push({
          title: extractTitleFromEntry(parsed.feed.entry[key]),
          email: extractEmailFromEntry(parsed.feed.entry[key]),
          phoneNumber: extractPhoneNumberFromEntry(parsed.feed.entry[key])
        })
      }
    })

    onSuccess(results)
  }

  signIn(e) {
    const {
      clientId,
      cookiePolicy,
      loginHint,
      hostedDomain,
      redirectUri,
      discoveryDocs,
      onRequest,
      onFailure,
      uxMode,
      accessType,
      responseType,
      prompt,
      onSuccess
    } = this.props

    const params = {
      client_id: clientId,
      cookie_policy: cookiePolicy,
      login_hint: loginHint,
      hosted_domain: hostedDomain,
      discoveryDocs,
      ux_mode: uxMode,
      redirect_uri: redirectUri,
      scope: SCOPE,
      access_type: accessType
    }

    if (responseType === 'code') {
      params.access_type = 'offline'
    }

    if (e) {
      e.preventDefault() // to prevent submit if used within form
    }
    if (!this.state.disabled) {
      const _signIn = () => {
        const auth2 = window.gapi.auth2.getAuthInstance()
        const options = { prompt }
        onRequest()
        if (responseType === 'code') {
          auth2.grantOfflineAccess(options).then(res => onSuccess(res), err => onFailure(err))
        } else {
          auth2.signIn(options).then(res => this.handleImportContacts(res), err => onFailure(err))
        }
      }

      window.gapi.load('auth2', () => {
        if (!window.gapi.auth2.getAuthInstance()) {
          window.gapi.auth2.init(params).then(_signIn)
        } else {
          _signIn()
        }
      })
    }
  }

  render() {
    const { tag, type, className, disabledStyle, buttonText, children, render, theme, icon } = this.props
    const disabled = this.state.disabled || this.props.disabled

    if (render) {
      return render({ onClick: this.signIn })
    }

    const initialStyle = {
      backgroundColor: theme === 'dark' ? 'rgb(66, 133, 244)' : '#fff',
      display: 'inline-flex',
      alignItems: 'center',
      color: theme === 'dark' ? '#fff' : 'rgba(0, 0, 0, .54)',
      boxShadow: '0 2px 2px 0 rgba(0, 0, 0, .24), 0 0 1px 0 rgba(0, 0, 0, .24)',
      padding: 0,
      borderRadius: 2,
      border: '1px solid transparent',
      fontSize: 14,
      fontWeight: '500',
      fontFamily: 'Roboto, sans-serif'
    }

    const hoveredStyle = {
      cursor: 'pointer',
      opacity: 0.9
    }

    const activeStyle = {
      cursor: 'pointer',
      backgroundColor: theme === 'dark' ? '#3367D6' : '#eee',
      color: theme === 'dark' ? '#fff' : 'rgba(0, 0, 0, .54)',
      opacity: 1
    }

    const defaultStyle = (() => {
      if (disabled) {
        return Object.assign({}, initialStyle, disabledStyle)
      }

      if (this.state.active) {
        if (theme === 'dark') {
          return Object.assign({}, initialStyle, activeStyle)
        }

        return Object.assign({}, initialStyle, activeStyle)
      }

      if (this.state.hovered) {
        return Object.assign({}, initialStyle, hoveredStyle)
      }

      return initialStyle
    })()
    const googleLoginButton = React.createElement(
      tag,
      {
        onMouseEnter: () => this.setState({ hovered: true }),
        onMouseLeave: () => this.setState({ hovered: false, active: false }),
        onMouseDown: () => this.setState({ active: true }),
        onMouseUp: () => this.setState({ active: false }),
        onClick: this.signIn,
        style: defaultStyle,
        type,
        disabled,
        className
      },
      [
        icon && <Icon key={1} active={this.state.active} />,
        <ButtonContent icon={icon} key={2}>
          {children || buttonText}
        </ButtonContent>
      ]
    )

    return googleLoginButton
  }
}


export default GoogleContacts

在React项目中,我需要登录gamil并获取我找到的名为Googlecontacts软件包的用户的联系人。这是GoogleContacts软件包的代码,用于从Google API获取联系人,但是却出现403错误。此错误表明我的范围是错误的!我尝试了很多示波器,但没有得到gamil的联系。 Google联系人的合适范围是什么?

javascript reactjs google-api google-api-client google-contacts-api
1个回答
0
投票

Google联系人API要求您的用户授予您的应用访问以下范围之一的联系人数据的权限

enter image description here

您似乎正在使用

const SCOPE = 'https://www.googleapis.com/auth/spreadsheets.readonly'

这不会授予您访问权限,而Google仅与用户联系他们的Google表格。以下消息告诉您的是哪]

请求对Google联系人的身份验证范围不足

© www.soinside.com 2019 - 2024. All rights reserved.