Twilioからのバリデーションリクエスト
要するに以下の様なときに使うやつです。
(サーバが)受け取るHTTPリクエストが確かにTwilioからのものであり、不審な第三者からのものではないことを確実にしたい
詳細はTwilioドキュメントを御覧ください。
やり方
routes.rb を設定する
twilioからのリクエストを受けるルートは、何か適当なnamespaceをつけるのをオススメします。
Rails.application.routes.draw do
namespace :phone do
post 'incoming', to: 'incoming#new', format: true
end
end
configを設定する
configにtwilioのAPIを使うためのキーを設定します。
(実際はソース上に直に書いたりはしないと思います)
Twilio.configure do |config|
config.account_sid = 'account_sid'
config.auth_token = 'auth_token'
end
application_controller.rb を書く
Twilio用のapplication_controller.rbを作成します。ここでvalidationをします。
class Phone::ApplicationController < ApplicationController
protect_from_forgery with: :null_session
before_action :validate_incoming_requests, if: -> { !(Rails.env.test? || Rails.env.development?) }
RequestValidationError = Class.new(StandardError)
rescue_from RequestValidationError, with: :handle_401
private
def validate_incoming_requests
return unless request.post?
validator = Twilio::Util::RequestValidator.new
signature = request.headers['X-Twilio-Signature']
fail RequestValidationError unless validator.validate(request.url, request.request_parameters, signature)
end
def handle_401
render xml: reject_twiml, status: 401
end
def reject_twiml
Twilio::TwiML::Response.new do |r|
r.Reject reason: :busy
end.text
end
end
Controller.rb を書く
ここではvalidationを意識する必要は有りません。
Twilio用のapplication_controller.rbを継承するのをお忘れなく。
class Phone::IncomingController < Phone::ApplicationController
def new
# 本当はpostらしい処理を書く
render xml: say_twiml
end
private
def say_twiml
Twilio::TwiML::Response.new do |r|
r.Say 'It is fine today.'
end.text
end
end
注意点
namespaceに"twilio"を使わない
その名前はtwilio-rubyジェムで使われています。問題ないとは思いますが、避けるに越したことは有りません。また、大抵の場合はもっとアプリケーションに適した名前があります。
バリデーションの際にrequest.paramsを使わない
request.params
を使うとvalidationが失敗します。request.params
にはrailsで追加したcontroller
やaction
などが含まれているからです。
なので、上記のソースではrequest.request_parameters
を使用しています。これはrailsで追加した値は含みません。
参考
Railsのparamsからcontrollerとかpathに関係するパラメータを除きたい
Validate Incoming Requests - twilio-ruby