Google Actions使用Python推送通知吗?

时间:2018-12-04 22:40:00

标签: python-3.x google-cloud-platform google-oauth dialogflow actions-on-google

我正在尝试弄清楚如何使用DialogFlow / Google Actions启动推送通知。我整理了一些测试代码,但是当我对其进行测试时,我得到了“ 403 Forbidden”响应。有人可以为我提供一个很好的示例,说明如何使用Python 3进行此操作。

`

import urllib.request
import json

notification = {
    'userNotification': {
        'title': 'Test Notification',
    },
    'target': {
        'userId': 'user-id here',
        'intent': 'Notification Intent',
        'locale': 'en-US',
    }
}


my_url = 'https://actions.googleapis.com/v2/conversations:send'
access_token = 'access token here'

request = urllib.request.Request(my_url)
request.add_header('Content-Type', 'application/json; charset=utf-8')
payload = { 'auth': { 'bearer': access_token },
             'json': 'true',
             'body': { 'customPushMessage': notification, 'isInSandbox': 
             'true' } };

jsondata = json.dumps(payload)
jsondataasbytes = jsondata.encode('utf-8')
response = urllib.request.urlopen(request, jsondataasbytes)

`

有人可以提供有关如何使其正常工作的建议吗?

================================================ =============

更新:我按照建议修改了auth标头,现在我得到的是“ 401:Unauthorized”。我不确定是否正确创建了访问令牌。这是我的操作方式:

我在Google Console网站上创建了RSA256私钥。我使用该密钥对包含以下字段的JWT进行编码:

{
    "iss": [
        "My Service Name",
        "\"my_service-account@service_name.iam.gserviceaccount.com\""
    ],
    "iat": 1544018697,
    "exp": 1544019898,
    "aud": 
"https://www.googleapis.com/auth/actions.fulfillment.conversation\"",
    "sub": [
        "Push Notification",
        "\"my-service-account@service_name.iam.gserviceaccount.com\""
    ]
}

我不知道这是否正确:所有这些的文档很难整理。

更新2:

我修改了Prisoner建议的代码,现在我可以获取似乎有效的access_token了。这是修改后的代码:

from oauth2client.client import GoogleCredentials

service_account_file = 'path-to-service_account_file'
credentials = GoogleCredentials.from_stream(SERVICE_ACCOUNT_FILE)

access_token = credentials.get_access_token().access_token

当我尝试使用访问令牌时,我仍然收到“ 401未经授权”响应。有人真的这样做过吗?如果是这样,您能给我一些有关要使用的正确URL以及如何格式化urllib.request消息的详细信息吗?

2 个答案:

答案 0 :(得分:1)

您已将一些属于标头的内容放入请求的正文中。特别是,“ 403 forbidden”表明Authorization标头是错误的还是丢失的,在您的情况下,由于您试图将其放入正文中,因此看起来好像丢失了。 / p>

您要发送的内容正文应仅包含带有customPushMessage属性的JSON。

我对python不太熟悉,但我认为类似的东西更是您想要的:

request = urllib.request.Request(my_url)
request.add_header('Authorization', 'bearer '+access_token)
request.add_header('Content-Type', 'application/json; charset=utf-8')
payload = { 'customPushMessage': notification }

jsondata = json.dumps(payload)
jsondataasbytes = jsondata.encode('utf-8')
response = urllib.request.urlopen(request, jsondataasbytes)

如果您继续收到“ 403 Forbidden”消息,请确保您的access_token是最新的,并且实际上是访问令牌。访问令牌是通过服务帐户密钥创建的,但不是密钥本身。它们的寿命有限(通常为1小时),而钥匙则是持久的。

更新,有关通过密钥生成访问令牌。

您不能只创建并签名JWT用作访问令牌。

最简单的方法是使用Google APIs Client Library for Python,其中包括一个用于处理OAuth with service accounts的库。

我还没有测试过,但是您应该能够执行类似的操作,将SERVICE_ACCOUNT_FILE设置为密钥的存储位置。

from google.oauth2 import service_account

SCOPES = ['https://www.googleapis.com/auth/actions.fulfillment.conversation']
SERVICE_ACCOUNT_FILE = '/path/to/service.json'

credentials = service_account.Credentials.from_service_account_file(
        SERVICE_ACCOUNT_FILE, scopes=SCOPES)

access_token = credentials.get_access_token()

答案 1 :(得分:0)

好的,我已经弄清楚了如何获取access_token,从而解决了部分问题。我遇到了另一个问题,即我的测试帐户无法获得更新权限,但是我将发布一个新问题来解决这个问题。我从另一个答案改编了代码,这似乎可行:

# Adapted from https://stackoverflow.com/questions/51821919/how-to-send-push-notification-from-google-assistant-through-dialogflow-fulfilmen/51961677#51961677

import io
import json

import requests
from google.oauth2 import service_account
import google.auth.transport.requests

def send_notification(path_to_service_account="default", intent="default"):
    if path_to_service_account == "default":
        PATH_TO_SERVICE_ACCOUNT = 'path to downloaded service account json file from Google Cloud Console'
    else:
        PATH_TO_SERVICE_ACCOUNT = path_to_service_account

    if intent == "default":
        INTENT = 'Notification Intent'
    else:
        INTENT = intent

    REQUIRED_SCOPE = 'https://www.googleapis.com/auth/actions.fulfillment.conversation'
    USER_ID = 'user id here'
    INTENT = 'Your intent name'

    # Get access token
    with io.open(PATH_TO_SERVICE_ACCOUNT, 'r', encoding='utf-8') as json_fi:
        credentials_info = json.load(json_fi)
    credentials = service_account.Credentials.from_service_account_info(
        credentials_info, scopes=[REQUIRED_SCOPE])
    request = google.auth.transport.requests.Request()
    credentials.refresh(request)

    headers = {
        'Authorization': 'Bearer ' + credentials.token
    }

    payload = {
        'customPushMessage': {
            'userNotification': {
                'title': 'App Title',
                'text': 'Simple Text'
            },
            'target': {
                'userId': USER_ID,
                'intent': INTENT,
                # Expects a IETF BCP-47 language code (i.e. en-US)
                'locale': 'en-US'
            }
        }
    }

    r = requests.request("POST", 'https://actions.googleapis.com/v2/conversations:send', data=json.dumps(payload), headers=headers)

    print(str(r.status_code) + ': ' + r.text)