Создание новой коллекции и документа с помощью Firestore REST API, возвращающего HTTP 400 - PullRequest
0 голосов
/ 31 мая 2019

Привет сообщество stackoverflow,

Я использую Firestore, а не базу данных в реальном времени для тестового проекта, над которым я работаю.

  • Для начала я пытаюсь создать новый документ внутри существующей коллекции и проекта, который я создал вручную через веб-интерфейс. Идентификатор моего проекта newproject-30f72, а имя уже созданной коллекции - testcollection.
  • Я включил метод аутентификации Email/Password и зарегистрировал нового пользователя email-id/password. Правило для записи с включенной аутентификацией следующее:
service cloud.firestore {
  match /databases/{database}/documents {
    match /{document=**} {
      allow read, write: if request.auth.uid != null;
    }
  }
}

На данный момент, я не уверен, что для проверки правильности request.auth.uid != null достаточно одного только чёрного токена, переданного в заголовке, так что, скорее всего, моё правило также может быть неверным, так как я использовал симулятор для автоматической генерации правила , но я проверил, что правило не вызывает проблему, с которой я сталкиваюсь в данный момент, полностью отключив правило.

  • Я включил rules, чтобы только авторизованные пользователи могли писать в firestore (Под аутентификацией я подразумеваю idToken для определенного пользователя на основе email/password, а не apiKey для веб-приложения. Хотя я не знаю, возможно ли это.)
  • Я включил Add Firebase to your web app / register app, и это дало мне объект json с именем firebaseConfig со следующими подробностями.

   var firebaseConfig = {
      apiKey: "some_api_key",
      authDomain: "newproject-30f72.firebaseapp.com",
      databaseURL: "https://newproject-30f72.firebaseio.com",
      projectId: "newproject-30f72",
      storageBucket: "newproject-30f72.appspot.com",
      messagingSenderId: "111122223333",
      appId: "1:1111:web:2222"
   };  

Я использую apiKey из вышеуказанного объекта json, чтобы получить idToken, действительный в течение некоторого времени, для записи в базу данных firestore. Код для этого, как показано ниже в python3.

import json
from urllib import request, error
from collections import defaultdict

firebase_apikey = 'some_api_key'
auth_request_url = "https://www.googleapis.com/identitytoolkit/v3/relyingparty/verifyPassword?key={}".format(firebase_apikey)

class auth:
    def __init__(self, email: str, password: str):
        self.email = email
        self.password = password
        self.post_data = defaultdict()
        self.post_data['email'] = self.email
        self.post_data['password'] = self.password
        self.post_data['returnSecureToken'] = True
        self.headers = {"Content-Type": "application/json"}
        # print("POST DATA IS:: " + json.dumps(self.post_data))
        self.r = request.Request(auth_request_url,
                                 data=json.dumps(self.post_data).encode(),
                                 headers=self.headers)
        # self.url_open

    def get_auth_token(self):
        try:
            self.url_open = request.urlopen(self.r)
        except Exception as e:
            return e
        try:
            return json.loads(self.url_open.read())
        except Exception as e:
            return e


s = auth("someuser.somethingelse@gmail.com", "somepassword")
response = s.get_auth_token()
id_token = response['idToken']
expires_in = response['expiresIn']


Я получил idToken, представляющий собой строку длиной 924 символа.

Теперь я пытаюсь написать в firestore с idToken, который я получил и действителен в течение 3600 (я полагаю, секунд), используя заголовок Authorization': 'Bearer следующим образом.

firestore_project_url = "https://firestore.googleapis.com/v1beta1/projects/{}/databases/(default)/documents:write".format(
    'newproject-30f72')

headers = {
    'Content-type': 'application/json',
    'Authorization': 'Bearer %s' % id_token,
}

test_data = '''
{
    "writes": [{
        "updateMask": {
            "fieldPaths": ["name"]
        },
        "update": {
            "name": "projects/newproject-30f72/databases/(default)/documents/testcollection/testdoc/",
            "fields": {
                "name": {
                    "stringValue": "test"
                }
            }
        }
    }]
}
'''

test_data_json_bytes = json.dumps(test_data).encode("utf-8")
req = request.Request(url=firestore_project_url,
                      data=test_data_json_bytes,
                      headers=headers,
                      method='POST')
print(headers)
f = request.urlopen(req)

Я вижу заголовки как

{'Content-type': 'application/json', 'Authorization': 'Bearer eyJhbGciOiJSUzI1NiIsI........<snip>'}

но я получаю urllib.error.HTTPError: HTTP Error 400: Bad Request ошибку.

Я имел в виду Пример REST Firebase Firestore , чтобы проверить его, используя curl с пользовательскими заголовками, чтобы добавить токен носителя и посмотреть, есть ли возможное многословие, и я вижу

*   Trying 74.125.68.95...
* TCP_NODELAY set
* Connected to firestore.googleapis.com (74.125.68.95) port 443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* successfully set certificate verify locations:
*   CAfile: /etc/ssl/certs/ca-certificates.crt
  CApath: none
* TLSv1.3 (OUT), TLS handshake, Client hello (1):
* TLSv1.3 (IN), TLS handshake, Server hello (2):
* TLSv1.3 (IN), TLS handshake, Encrypted Extensions (8):
* TLSv1.3 (IN), TLS handshake, Certificate (11):
* TLSv1.3 (IN), TLS handshake, CERT verify (15):
* TLSv1.3 (IN), TLS handshake, Finished (20):
* TLSv1.3 (OUT), TLS change cipher, Change cipher spec (1):
* TLSv1.3 (OUT), TLS handshake, Finished (20):
* SSL connection using TLSv1.3 / TLS_AES_256_GCM_SHA384
* ALPN, server accepted to use h2
* Server certificate:
*  subject: C=US; ST=California; L=Mountain View; O=Google LLC; CN=*.googleapis.com
*  start date: May 14 13:35:00 2019 GMT
*  expire date: Aug  6 13:20:00 2019 GMT
*  subjectAltName: host "firestore.googleapis.com" matched cert's "*.googleapis.com"
*  issuer: C=US; O=Google Trust Services; CN=Google Internet Authority G3
*  SSL certificate verify ok.
* Using HTTP2, server supports multi-use
* Connection state changed (HTTP/2 confirmed)
* Copying HTTP/2 data in stream buffer to connection buffer after upgrade: len=0
* Using Stream ID: 1 (easy handle 0x560e5884af30)
> POST /v1beta1/projects/newproject-30f72/databases/(default)/documents/testcollection3 HTTP/2
> Host: firestore.googleapis.com
> User-Agent: curl/7.64.1
> Accept: */*
> {Content-type: application/json, Authorization: Bearer eyJhbGciOiJSUzI1NiIsImtpZCI6........<snip>}
> Content-Type: application/json
> Content-Length: 258
> 
* We are completely uploaded and fine
* TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
* TLSv1.3 (IN), TLS handshake, Newsession Ticket (4):
* old SSL session ID is stale, removing
* Connection state changed (MAX_CONCURRENT_STREAMS == 100)!
< HTTP/2 400 
< content-type: text/html; charset=UTF-8
< referrer-policy: no-referrer
< content-length: 1555
< date: Fri, 31 May 2019 14:31:36 GMT
< 
* HTTP/2 stream 0 was not closed cleanly: PROTOCOL_ERROR (err 1)
* stopped the pause stream!
* Connection #0 to host firestore.googleapis.com left intact
curl: (92) HTTP/2 stream 0 was not closed cleanly: PROTOCOL_ERROR (err 1)
* Closing connection 0

Я имел в виду ссылки на следующие ссылки.

https://groups.google.com/forum/#!topic/google-cloud-firestore-discuss/4Le2RskC3cg https://firebase.google.com/docs/firestore/reference/rest/v1beta1/projects.databases.documents/commit

Я пытаюсь достичь

  • используйте аутентификацию по электронной почте / паролю для аутентификации в firestore
  • создайте коллекцию и запишите в нее документы.

Любая помощь очень ценится.

Большое спасибо.

1 Ответ

1 голос
/ 03 июня 2019

ТАК это то, что у меня сработало (я использовал requests модуль, но чистый эффект тот же)

Сначала авторизуйтесь, точно так же, как вы.

url = "https://www.googleapis.com/identitytoolkit/v3/relyingparty/verifyPassword?key=" + API_KEY
payload = {"email": email, "password": password, "returnSecureToken": True}
rsp = requests.post(url, data=payload)
id_token = rsp.json().get("idToken")

# User idToken from your auth for later requests
headers = {
    'Content-type': 'application/json',
    'Authorization': "Bearer %s" % id_token
}

Теперь создайте документ в коллекции

# Create a doc in "testcoll"
url = "https://firestore.googleapis.com/v1beta1/projects/" + PROJECT + "/databases/(default)/documents/testcoll"
payload = {
  "fields": {
    "meaningOfLife": {"integerValue": 42}
  }
}
# Create Doc
rsp = requests.post(url, headers=headers, data = json.dumps(payload))
assert(rsp.status_code == 200)
docref = rsp.json().get("name")
print(rsp.json())

Теперь обновите тот же документ

# Update doc
url = "https://firestore.googleapis.com/v1beta1/" + docref
payload = {
  "fields": {
    "meaningOfLife": {"stringValue": '43'}
  }
}
rsp = requests.patch(url, headers=headers, data = json.dumps(payload))
assert(rsp.status_code == 200)
print(rsp.json())
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...