使用FastAPI(Python)向CKEditor提交评论时出现签名无效问题
问题:FastAPI调用CKEditor评论API时签名无效
我用FastAPI开发向CKEditor提交评论的服务时,遇到了签名无效的问题。获取所有评论的功能正常,但提交评论时返回401错误,提示"Invalid signature"。相关代码及响应如下:
添加评论服务代码
def add_comment_by_document_id(comment: request_schema.CreateComment): timestamp = int(time()) * 1000 comment_path = "comments" if comment.document_id is None else f"comments?document_id={comment.document_id}" ckeditor_url = get_ckeditor_url(comment_path).geturl() parsed_url = urlparse(ckeditor_url) path = parsed_url.path post_data = { "id": comment.id, "document_id": comment.document_id, "thread_id": comment.thread_id, "content": comment.content, "user": { "id": comment.user.id }, "thread": { "id": comment.thread.id } } signature = generateSignature("POST", path, timestamp, post_data) headers = { "X-CS-Signature": signature, "X-CS-Timestamp": str(timestamp) } response = requests.post(ckeditor_url, headers=headers, json=post_data) return response.json()
get_ckeditor_url函数
def get_ckeditor_url(url_param: str): url_param = CKEDITOR_API_URL + url_param url = urlparse(url_param) return url
生成签名函数
def generateSignature(method, url_param, timestamp, body): url = get_ckeditor_url(url_param) path = url.path if url.query: path += "?" + url.query methodUpperCase = method.upper() dataString = methodUpperCase + path + str(timestamp) if body: dataString += json.dumps(body, separators=(',', ':')) return hmacDigest(dataString, CKEDITOR_API_SECRET)
错误响应
{ "message": "Invalid signature.", "trace_id": "5b9a1eef-5cbb-4b59-bb6a-3ce5fbcd2a76", "status_code": 401, "data": { "signature": "<MyToken>" }, "level": "trace" }
注意事项
- 获取所有评论的功能可以正常工作。
- 已尝试复制CKEditor官方生成签名函数,但仍出现相同问题,且生成的签名不一致。
排查与解决方案
1. 修正签名生成的URL路径传递问题
你当前调用generateSignature时传入的是parsed_url.path(仅路径部分),但generateSignature内部会重新拼接完整URL并提取路径+查询参数,导致签名用的路径和实际请求的URL参数不一致(比如带document_id的场景)。
修复代码:
直接把完整的comment_path传给签名函数,避免重复解析导致的参数丢失:
# 原代码 signature = generateSignature("POST", path, timestamp, post_data) # 修改后 signature = generateSignature("POST", comment_path, timestamp, post_data)
2. 确保JSON序列化完全匹配CKEditor要求
CKEditor对签名中的JSON格式要求严格,需确认:
- 序列化后的字符串无多余空格(你已用
separators=(',', ':'),但要验证结果) - 字典键的顺序和官方示例完全一致(比如
id、document_id、thread_id的顺序不能乱)
验证方法:
打印序列化后的字符串,和CKEditor官方文档的示例对比:
print(json.dumps(post_data, separators=(',', ':')))
3. 检查服务器时间同步
签名校验对时间戳的容忍范围通常很小(比如30秒内),确保你的服务器时间和CKEditor服务器时间同步,避免因时间差导致签名失效。
4. 确认HMAC加密算法与编码
检查hmacDigest函数是否使用CKEditor要求的算法(通常是SHA-256),且输出编码(Base64或十六进制)和官方一致。示例实现:
import hmac import hashlib import base64 def hmacDigest(dataString, secret): hmac_obj = hmac.new(secret.encode('utf-8'), dataString.encode('utf-8'), hashlib.sha256) return base64.b64encode(hmac_obj.digest()).decode('utf-8')
5. 对比GET请求的签名逻辑
既然获取评论的GET请求正常,把GET请求的签名生成步骤和POST对比:
- 检查GET请求是否传递了正确的路径参数
- 确认POST请求的body是否被正确包含在签名字符串中,而GET请求无body的处理逻辑是否正确
内容的提问来源于stack exchange,提问作者VannHelloWorld
相关产品推荐
相关产品推荐

