Skip to main content
 首页 » 编程设计

python之使用返回 HTTP 400 的 Firestore REST API 创建新的集合和文档

2024年11月24日43qq78292959

你好 stackoverflow 社区,

我正在为我正在进行的测试项目使用 Firestore 而不是实时数据库。

  • 作为初学者,我尝试在我通过网络界面手动创建的现有集合和项目中创建一个新文档。我的项目 ID 是 newproject-30f72,已经创建的集合名称是 testcollection。
  • 我启用了Email/Password 身份验证方法,并且注册了一个新的email-id/password 用户。我对启用 auth 的写入的规则如下。
service cloud.firestore { 
  match /databases/{database}/documents { 
    match /{document=**} { 
      allow read, write: if request.auth.uid != null; 
    } 
  } 
} 

在这一点上,我不确定,仅在 header 中传递一个 barer token 就足以验证 request.auth.uid != null,所以我的规则很可能也是错误的,因为我使用模拟器自动生成规则,但我通过完全禁用规则验证了该规则不会导致我目前面临的问题。

  • 我启用了规则,这样只有经过身份验证的用户才能写入 firestore。 (通过身份验证,我指的是基于特定 email/password 的用户的 idToken,而不是网络应用程序的 apiKey。我不虽然不知道这是否可能。)
  • 我启用了将 Firebase 添加到您的网络应用程序/注册应用程序,这为我提供了一个名为 firebaseConfig 的 json 对象,其中包含以下详细信息。
 
   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" 
   };   
 

我正在使用上述 json 对象中的 apiKey 获取有效期为一段时间的 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 个字符长的字符串。

现在,我正在尝试使用 Authorization': 'Bearer header 使用我收到并在 3600 秒(我假设的秒数)内有效的 idToken 写入 firestore,如下所示.

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 错误。

我指的是 Firebase Firestore REST example使用带有自定义 header 的 curl 检查它以添加不记名 token 并查看是否有任何可能的冗长,我看到了

*   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

我想要实现的是

  • 使用电子邮件/密码 auth 获得 firestore 的身份验证
  • 创建集合并向其写入文档。

非常感谢任何帮助。

非常感谢。

请您参考如下方法:

所以这对我有用(我使用了 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())