You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.01 01:43:18