python - Slack 交互式消息:POST 请求有效负载具有意外的格式
问题描述
我在 Slack 的 Flask 应用程序中收到 POST 请求。当用户按下交互式消息按钮时发送请求。根据 Slack文档,我必须提取请求的正文以验证签名。不过,我计算的签名与 Slack 发送的签名不匹配。事实上,请求的主体是一些编码字符串。正如预期的那样,该字符串实际上是一个编码字典而不是查询 str 参数。
这是我观点的开始:
@app.route('/register', methods=['POST'])
def register_visit():
data = request.get_data()
signature = request.headers.get('X-Slack-Signature', None)
timestamp = request.headers.get('X-Slack-Request-Timestamp', None)
signing_secret = b'aaaaaaaaaaaaaaaa'
# old message, ignore
if round(actual_time.time() - float(timestamp)) > 60 * 5:
return
concatenated = ("v0:%s:%s" % (timestamp, data)).encode('utf-8')
computed_signature = 'v0=' + hmac.new(signing_secret, msg=concatenated, digestmod=hashlib.sha256).hexdigest()
if hmac.compare_digest(computed_signature, signature):
...
我试图格式化接收到的数据,使其看起来像:
token=fdjkgjl&user_id=1234...
但我不知道数据中必须存在的所有必要参数。
任何想法都受到高度赞赏。
消息的正文如下 - 在被 URL 解码后(注意我修改了可能的敏感数据):
b'payload={"type":"interactive_message","actions": [{"name":"yes_button","type":"button","value":"236"}],"callback_id":" visit_button","team":{"id":"fffff","domain":"ffff"},"channel":{"id":"ffff","name":"directmessage"},"user" :{"id":"ffffff","name":"fffft"},"action_ts":"1540403943.419120","message_ts":"1541403949.000100","attachment_id":"1","token":"8LpjBuv13J7xAjhl2lEajoBU" ,"is_app_unfurl":false,"original_message":{"text":"Test","bot_id":"DDDDDDDDD","附件":[{"callback_id":"visit_button","text":"注册","id":1,"color":"3AA3E3","actions":[{"id":"1" ,"name":"yes_button","text":"Yes","type":"button","value":"236","style":""}],"fallback":"Register"} ],"type":"message","subtype":"bot_message","ts":"1540413949.000100"},"response_url":"https://hooks.slack.com/actions/ffffff/ffffff/tXJjx1XInaUhrikj6oEzK08e" ,"trigger_id":"464662548327.425084163429.dda35a299eedb940ab98dbb9386b56f0"}'text":"Register","id":1,"color":"3AA3E3","actions":[{"id":"1","name":"yes_button","text":"Yes" ,"type":"button","value":"236","style":""}],"fallback":"Register"}],"type":"message","subtype":"bot_message ","ts":"1540413949.000100"},"response_url":"https://hooks.slack.com/actions/ffffff/ffffff/tXJjx1XInaUhrikj6oEzK08e","trigger_id":"464662548327.425084163429.dda35a299eedb940ab09'b'btext":"Register","id":1,"color":"3AA3E3","actions":[{"id":"1","name":"yes_button","text":"Yes" ,"type":"button","value":"236","style":""}],"fallback":"Register"}],"type":"message","subtype":"bot_message ","ts":"1540413949.000100"},"response_url":"https://hooks.slack.com/actions/ffffff/ffffff/tXJjx1XInaUhrikj6oEzK08e","trigger_id":"464662548327.425084163429.dda35a299eedb940ab09'b'byes_button","text":"是","type":"button","value":"236","style":""}],"fallback":"Register"}],"type": "消息","子类型":"bot_message","ts":"1540413949.000100"},"response_url":"https://hooks.slack.com/actions/ffffff/ffffff/tXJjx1XInaUhrikj6oEzK08e","trigger_id":" 464662548327.425084163429.dda35a299eedb940ab98dbb9386b56f0"}'yes_button","text":"是","type":"button","value":"236","style":""}],"fallback":"Register"}],"type": "消息","子类型":"bot_message","ts":"1540413949.000100"},"response_url":"https://hooks.slack.com/actions/ffffff/ffffff/tXJjx1XInaUhrikj6oEzK08e","trigger_id":" 464662548327.425084163429.dda35a299eedb940ab98dbb9386b56f0"}'response_url":"https://hooks.slack.com/actions/ffffff/ffffff/tXJjx1XInaUhrikj6oEzK08e","trigger_id":"464662548327.425084163429.dda35a299eedb940ab98dbb9386b56f0"}'response_url":"https://hooks.slack.com/actions/ffffff/ffffff/tXJjx1XInaUhrikj6oEzK08e","trigger_id":"464662548327.425084163429.dda35a299eedb940ab98dbb9386b56f0"}'
解决方案
您获得“乱码”数据的原因是您正在使用request.get_data()
. 该方法将返回请求的原始数据,但不会为您进行任何解码。
更方便的是使用request.form.get('payload')
,它会直接给你请求对象的 JSON 字符串。然后,您可以将其转换为 dict 对象,json.loads()
以便在您的应用程序中进一步处理它。
请注意,您收到的格式是交互式消息的正确格式。您不会得到您所建议的查询字符串(例如“token=abc;user_id?def...”)(例如斜杠命令请求)。交互式消息请求将始终将请求作为 JSON 字符串包含在有效负载表单属性中。请参阅此处以供参考。
这是一个简单的工作示例,它将向按下按钮的用户回复问候。它将直接与 Slack 一起工作,但我建议使用Postman来测试它。
#app.py
from flask import Flask, request #import main Flask class and request object
import json
app = Flask(__name__) #create the Flask app
@app.route('/register', methods=['POST'])
def register_visit():
slack_req = json.loads(request.form.get('payload'))
response = '{"text": "Hi, <@' + slack_req["user"]["id"] + '>"}'
return response, 200, {'content-type': 'application/json'}
if __name__ == '__main__':
app.run(debug=True, port=5000) #run app in debug mode on port 5000
推荐阅读
- javascript - 更改子菜单的可见性 onClick -- getElementsByClassName
- kubernetes - Gitlab管道失败
- c++ - 确定模板中模板参数的类型
- python - Pandas:遍历列表以匹配数据框中的值
- flutter - 颤振按钮 onPressed() 未在 GestureDetector 中触发
- certificate - 在 Azure 容器实例上设置 TLS SSL 版本 1.2
- c# - UI 不保留 Blazor 中所选项目的复选框值
- javascript - 具有多种测量选项的体积计算器
- html - 如何在为 ap 标签创建新行之前添加字符限制
- css - 与 target="_blank" 的链接仍然受到伪类的影响:用户点击后的悬停样式,仅限 Chrome