松弛的交互消息:POST请求有效载荷的格式意外

时间:2018-10-24 01:41:02

标签: python flask slack-api

我在Slack的Flask应用程序中收到POST请求。当用户按下交互式消息按钮时,将发送请求。根据Slack docs,我必须提取请求的主体以验证签名。 我的计算出的签名与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”,“令牌”:“ 8LpjBuv13J7xAjhl2lEajoBU”,“ is_app_unfurl”:false,“原始文本”:{测试”,“ bot_id”:“ DDDDDDDDD”,“附件”:[{“ callback_id”:“ visit_button”,“ text”:“ Register”,“ id”:1,“ color”:“ 3AA3E3”,“ actions” :[{“ id”:“ 1”,“名称”:“ yes_button”,“ text”:“是”,“ 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“}'

2 个答案:

答案 0 :(得分:2)

获取“乱码”数据的原因是您正在使用request.get_data()。该方法将返回请求的原始数据,但不会为您做任何解码。

使用request.form.get('payload')更为方便,它将直接为您提供请求对象的JSON字符串。然后,您可以使用json.loads()将其转换为dict对象,以在您的应用中进一步处理它。

请注意,您收到的格式是交互式消息的正确格式。您将不会得到您建议的查询字符串(例如“ token = abc; user_id?def ...”)(例如用于斜杠命令请求)。交互式消息请求将始终将请求作为JSON字符串包含在有效载荷表单属性中。请参阅here以供参考。

这是一个简单的工作示例,它将向按下按钮的用户致以问候。它可以直接与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

答案 1 :(得分:1)

好的,问题与Slack向我发送消息的方式无关。这是关于误解了哪些数据以字节为单位,哪些数据是unicode。在我的案例中,罪魁祸首是字符串格式-行concatenated = ("v0:%s:%s" % (timestamp, data)).encode('utf-8')应该是concatenated = (b"v0:%b:%b" % (timestamp.encode("utf-8"), data))。数据已经是字节,而时间戳是unicode。 不敢相信我已经为此努力了数小时-_-

@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 = (b"v0:%b:%b" % (timestamp.encode("utf-8"), data))
    computed_signature = 'v0=' + hmac.new(signing_secret, msg=concatenated, 
    digestmod=hashlib.sha256).hexdigest()
    if hmac.compare_digest(computed_signature, signature):
        ...