CloudKit 服务器到服务器身份验证:不断收到 401 身份验证失败
CloudKit Server-to-Server auth: Keep getting 401 Authentication failed
我最近一直在探索 CloudKit 和相关框架。我与我的应用程序以及使用 CloudKitJS 的网站进行了通信。我挣扎的地方是服务器到服务器的通信(我需要从public数据库导出数据到csv。
我试过 Python 软件包 requests-cloudkit,这是其他人建议的。我已经创建了一个服务器到服务器令牌,并在创建 eckey.pem 文件后仅复制了 START 和 END 行之间的密钥。然后我得到了这个代码:
from requests_cloudkit import CloudKitAuth
from restmapper import restmapper
import json
KEY_ID = '[my key ID from CK Dashboard]'
SECRET_FILE_KEY = 'eckey.pem'
AUTH = CloudKitAuth(KEY_ID, SECRET_FILE_KEY)
PARAMS = {
'query':{
'recordType': '[my record type]'
},
}
CloudKit = restmapper.RestMapper("https://api.apple-cloudkit.com/database/1/[my container]/development/")
cloudkit = CloudKit(auth=AUTH)
response = cloudkit.POST.public.records.query(json.dumps(PARAMS))
然后我收到 401 身份验证失败 响应。我坚持了好几天,所以如果有任何帮助或建议,我将不胜感激。
创建 server-to-server 密钥是重要的第一步,但之后要发出 HTTP 请求,您必须对每个请求签名。
在 this documentation page 底部附近查找 验证 Web 服务请求 部分。
这有点复杂,但您必须仔细构造 signed headers 以包含您发出的每个请求。我不熟悉如何在 Python 中执行此操作,但这是我在 NodeJS 中执行此操作的方法,这可能会有所帮助:
//Get the timestamp in a very specific format
let date = moment().utc().format('YYYY-MM-DD[T]HH:mm:ss[Z]')
//Construct the subpath
let endpoint = '/records/lookup'
let path = '/database/1/iCloud.*****/development/public'
let subpath = path+endpoint
//Get the key file
let privateKeyFile = fs.readFileSync('../../'+SECRET_FILE_KEY, 'utf8')
//Make a string out of your JSON query
let query = {
recordType: '[my record type]'
}
let requestBody = JSON.stringify(query)
//Hash the query
let bodyHash = crypto.createHash('sha256').update(requestBody, 'utf8').digest('base64')
//Assemble the components you just generated in a special format
//[Current date]:[Request body]:[Web service URL subpath]
let message = date+':'+bodyHash+':'+subpath
//Sign it
let signature = crypto.createSign('RSA-SHA256').update(message).sign(privateKeyFile, 'base64')
//Assemble your headers and include them in your HTTP request
let headers = {
'X-Apple-CloudKit-Request-KeyID': KEY_ID,
'X-Apple-CloudKit-Request-ISO8601Date': date,
'X-Apple-CloudKit-Request-SignatureV1': signature
}
起初这有点毛茸茸,但我只是将所有这些东西放在一个函数中,以便在我需要发出请求时重复使用。
Apple 的文档几乎已被废弃,现在很难找到有关 CloudKit Web 服务的好帮助。
我最近一直在探索 CloudKit 和相关框架。我与我的应用程序以及使用 CloudKitJS 的网站进行了通信。我挣扎的地方是服务器到服务器的通信(我需要从public数据库导出数据到csv。
我试过 Python 软件包 requests-cloudkit,这是其他人建议的。我已经创建了一个服务器到服务器令牌,并在创建 eckey.pem 文件后仅复制了 START 和 END 行之间的密钥。然后我得到了这个代码:
from requests_cloudkit import CloudKitAuth
from restmapper import restmapper
import json
KEY_ID = '[my key ID from CK Dashboard]'
SECRET_FILE_KEY = 'eckey.pem'
AUTH = CloudKitAuth(KEY_ID, SECRET_FILE_KEY)
PARAMS = {
'query':{
'recordType': '[my record type]'
},
}
CloudKit = restmapper.RestMapper("https://api.apple-cloudkit.com/database/1/[my container]/development/")
cloudkit = CloudKit(auth=AUTH)
response = cloudkit.POST.public.records.query(json.dumps(PARAMS))
然后我收到 401 身份验证失败 响应。我坚持了好几天,所以如果有任何帮助或建议,我将不胜感激。
创建 server-to-server 密钥是重要的第一步,但之后要发出 HTTP 请求,您必须对每个请求签名。
在 this documentation page 底部附近查找 验证 Web 服务请求 部分。
这有点复杂,但您必须仔细构造 signed headers 以包含您发出的每个请求。我不熟悉如何在 Python 中执行此操作,但这是我在 NodeJS 中执行此操作的方法,这可能会有所帮助:
//Get the timestamp in a very specific format
let date = moment().utc().format('YYYY-MM-DD[T]HH:mm:ss[Z]')
//Construct the subpath
let endpoint = '/records/lookup'
let path = '/database/1/iCloud.*****/development/public'
let subpath = path+endpoint
//Get the key file
let privateKeyFile = fs.readFileSync('../../'+SECRET_FILE_KEY, 'utf8')
//Make a string out of your JSON query
let query = {
recordType: '[my record type]'
}
let requestBody = JSON.stringify(query)
//Hash the query
let bodyHash = crypto.createHash('sha256').update(requestBody, 'utf8').digest('base64')
//Assemble the components you just generated in a special format
//[Current date]:[Request body]:[Web service URL subpath]
let message = date+':'+bodyHash+':'+subpath
//Sign it
let signature = crypto.createSign('RSA-SHA256').update(message).sign(privateKeyFile, 'base64')
//Assemble your headers and include them in your HTTP request
let headers = {
'X-Apple-CloudKit-Request-KeyID': KEY_ID,
'X-Apple-CloudKit-Request-ISO8601Date': date,
'X-Apple-CloudKit-Request-SignatureV1': signature
}
起初这有点毛茸茸,但我只是将所有这些东西放在一个函数中,以便在我需要发出请求时重复使用。
Apple 的文档几乎已被废弃,现在很难找到有关 CloudKit Web 服务的好帮助。