我在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“}'
答案 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):
...