💃
Lambda上で動くPythonにてSlack Appからのリクエストを検証する
ネットを調べると、こちら の記事を元ネタに作り込まれている方が割と出てきますが、
Python Slack SDK に当該処理をやってくれる便利クラスがあるのでご紹介です
めっちゃ小ネタですが忘れがちなので備忘メモ✍
方法
Serverless FrameworkなどでAPI Gatewayからのリクエストを受け付けるケースを仮定します
Slack Appをワークスペースに追加した際に作成される Signing Secret
が必要となるので、環境変数など任意の方法でLambdaに渡してあげます
また、今回の話とは関係ないですが、Slackのリクエストタイムアウトは3秒と短いので、 async: true
にして非同期受け付けにするとそこそこ長い処理でも扱えるようになるものと思います
serverless.yml
service: example
frameworkVersion: "2"
provider:
name: aws
runtime: python3.8
lambdaHashingVersion: 20201221
region: ap-northeast-1
timeout: 60
memorySize: 256
environment:
SLACK_OAUTH_TOKEN: ${env:SLACK_OAUTH_TOKEN}
SLACK_SIGNING_SECRET: ${env:SLACK_SIGNING_SECRET}
functions:
main:
handler: main.handler
events:
- http:
path: example
method: post
async: true
plugins:
# pipenvでライブラリ管理ができるのでオススメ
- serverless-python-requirements
custom:
pythonRequirements:
dockerizePip: true
本記事のキモです
slack_sdk
にて SignatureVerifier
というクラスが用意されており、こちらを使うと引数にオブジェクト等を渡すだけで検証をしてもらえるのですが、
Api Gatewayから来るイベントは、 event['body']
がDictのため、そのままだと is_valid_request
関数に渡すことができないため、URLエンコードを施します
main.py
import json
import os
from urllib.parse import urlencode
from slack_sdk import WebClient
from slack_sdk.signature import SignatureVerifier
SLACK_OAUTH_TOKEN = os.environ['SLACK_OAUTH_TOKEN']
SLACK_SIGNING_SECRET = os.environ['SLACK_SIGNING_SECRET']
def handler(event, context):
"""
eventはこんな値が来る
{
"body": {
"xxx": "xxx",
"yyy": "yyy"
},
"headers": {
"x-slaxk-xxx": "xxx"
"y-slaxk-yyy": "yyy"
},
その他は略
}
"""
print(json.dumps(event))
# ポイント1: このクラスを使うと楽
signature_verifier = SignatureVerifier(signing_secret=SLACK_SIGNING_SECRET)
# ポイント2: bodyはURLエンコードして渡す
encoded_body = urlencode(event['body'])
if not signature_verifier.is_valid_request(body=encoded_body, headers=event['headers']):
# リクエスト検証に失敗
return {
'statusCode': 403,
'body': json.dumps({})
}
# インストールをおこなったSlackワークスペースからのリクエストであることが保証される
web_client = WebClient(token=SLACK_OAUTH_TOKEN)
# ユースケースに合わせていろいろする
return {
'statusCode': 200,
'body': json.dumps({})
}
お試しを🍛
Discussion