前回stripeを利用してDjangoでの決済機能を実装できました。よく利用するサービスにはいくら使ったなどの通知が私たちのスマホに届くはずです。そこで今回はstripe webhookを利用して決済した後にメールで通知できるようにします。
Djangoで決済自体を行う方法を知りたい人はこちらの記事を参照してください。
Table of Contents
なぜStripe webhookを使うのか?
Stripeの処理にclass Success_viewがあるなら、そこに処理を書けば、わざわざwebhookを利用する必要なくない?と思う方もいるでしょう。Success Viewに書き込むのはリロード攻撃を受けてしまったり、何らかの原因でSuccessViewに飛ばなかった場合、当然ですがお金を払っただけで何も返ってこないだけになる可能性があります。
リロード攻撃とは何か?
リロード攻撃(別名F5攻撃)とは何か、といっても名前で想像するのとおりリロードボタンを押すことでサーバーに圧をかけて落とす攻撃ですが、SuccessViewにメール送信を行う処理を行うと(1回の決済×リロードした回数分メール送信)が送られてしまします。そういうことを避けるためにstripeが用意した手段としてstripe Webhookという機能を使って不正なことをしてないかの検査を行った上でメールを送信するということを行います。
Emailの送信方法
メール送信にはさまざまなやり方がありますが今回は、Email Messageを利用します。またメールの送信方法をまとめた記事は別途に用意します。今回はwebhookを使って決済後にメールを送信する方法をメインで行うので、細かい設定方法は省略させていただきます。
下記のコードを入力してEmailを送る準備をします。
from django.core.mail import EmailMessage
StripeCliを使う
StripeCliをインストールする
stripe webhook を利用するためには、まずPCの方にStripeCliをインストールする必要があります。brewでインストールができるのでインストールをしていきます。
brew install stripe/stripe-cli/stripe
ちなみにpipでもstripeはありますが、stripe no commandと出るのでbrew でインストールしたほうがいいです。
Stripeにログインする
既にstripeをインストールしてログインしている場合は無視で問題ありませんがログインしていない場合はコマンドでログインすることが可能です。
stripe login
ログインが完了したらローカル用に設定します。下記のコマンドを入力するだけで完了します。//
stripe listen --forward-to http://127.0.0.1:8000/webhook/
http://127.0.0.1:8000/webhook/にてWebhookとのつながります。また、コマンド入力した後にライセンスキーみたいなのが発行されるので忘れずにメモをしといてください。次にsettings.pyを開き、ライセンスキーを設定しておきます。ちなみにdjango sslserverを使っている場合は、 処理を書き込んでも正常に動作しません。ユーザー機能がある場合は一度ログアウトを行った上で閉じてrunserverを起動させてください。(そうしないとログインした時にCSRF TOKEN エラーが発生してログインできなくなります。)
DJSTRIPE_WEBHOOK_SECRET = "whsec_xxx"
Views.pyにWebhookの処理を書く
次にViews.pyにwebhookにどうして欲しいのかを書き込んでいきます。
from django.views.decorators.csrf import csrf_exempt #CSRFTOKEN を無効化
....
stripe.api_key = settings.STRIPE_SECRET_KEY
# You can find your endpoint's secret in your webhook settings
endpoint_secret =settings.DJSTRIPE_WEBHOOK_SECRET
....
@csrf_exempt
def my_webhook_view(request):
payload = request.body
event = None
try:
event = stripe.Event.construct_from(
json.loads(payload), stripe.api_key)
except ValueError as e:
# Invalid payload
return HttpResponse(status=400)
except stripe.error.SignatureVerificationError as e:
# Invalid signature
return HttpResponse(status=400)
# Handle the checkout.session.completed event
if event['type'] == 'checkout.session.completed':
session = event['data']['object']
seiion_id = session['id']
lineitem = stripe.checkout.Session.list_line_items(seiion_id,limit=5,)
session_op =lineitem['data'][0]
game_title =session_op['description']
user_data = session['customer_email']
# Fulfill the purchase...
subject = "購入のお知らせ"
message = "Thank you bought for "+str(video_title)
from_email = 'MyEmail address'
recipient_list =user_data # 宛先
email = EmailMessage(subject, message, from_email, recipient_list,)
email.send()
# Passed signature verification
return HttpResponse(status=200)
全体のコードはこんな感じで打ち込めば完了です。
def my_webhook_view(request):
payload = request.body
event = None
try:
event = stripe.Event.construct_from(
json.loads(payload), stripe.api_key)
except ValueError as e:
# Invalid payload
return HttpResponse(status=400)
except stripe.error.SignatureVerificationError as e:
# Invalid signature
return HttpResponse(status=400)
djangoは仕様上ユーザー情報などの機密性の高いものにはcsrf_tokenが使われてないものは危険と判断して弾く性質があります。それらに例外を与えるためコードが@csrf_exemptです。これより下はcsrf_tokenが必要でも守りませんよと書き込むことができます。あとは公式に沿って打ち込みます。
if event['type'] == 'checkout.session.completed':
session = event['data']['object']
session_id = session['id']
lineitem = stripe.checkout.Session.list_line_items(session_id,limit=5,)
session_op =lineitem['data'][0]
game_title =session_op['description']
user_data = session['customer_email']
# Fulfill the purchase...
subject = "購入のお知らせ"
message = "Thank you bought for "+str(game_title)
from_email = 'MyEmail address'
recipient_list =user_data # 宛先
商品のデータを取得するにはstripe.checkout.Session.list_line_items(セッションID,)を使うことで、商品データの取得を行います。ただし取得するにはセッションIDが必要になるので、辞書の中にあるIDを取り出し、stripe.checkout.Session.list_line_itemsに当てはめます。stripe.checkout.Session.list_line_itemsの中身は辞書とリストが複雑に絡み合っているので取り出したい情報をサルベージする必要があります。
stripe.checkout.Session.list_line_itemsのデータそのままを引っ張ってくるとこんな感じになります。
辞書の中にあるリストを選択し、リストの中にある辞書のデータをピックアップするとこうなります。
urls.pyを書き込む
これでメール送信を行うことが完了できましたが、送り先であるurlがないとwebhook側が404コード「ねぇよ!そんなもん」と言ってくるので、urls.pyに書き込みます。
path('webhook/', views.my_webhook_view, name='stripe-webhook'),
これで購入時にメール送信を行う処理は完了です!!
参考にしたサイト
https://stripe.com/docs/api/checkout/sessions/line_items
https://stripe.com/docs/payments/checkout/fulfill-orders
宣伝
これらの技術をフル動員したゲームプレイ動画投稿サイトForbindeを開発公開しています。視聴者がゲーム実況者やゲーム開発者のゲームPVを視聴者がお金を払って宣伝すると投稿者の収益だけではなく、そのゲームの開発者にも収益が行くサイトを目指して活動しています。ご興味を持ちましたら是非動画を投稿してください