SNSのHTTP通知ハンドラーをforce.com Sitesで作って、HTTP通知の中でTwilio API呼び出してSMS送信するような処理を作ってみました。
SNSからSMS送信できるのは米国の電話番号だけっぽいので日本の電話番号に対応できるように、Twilio API経由でSMS送信するっていうのが目的。
流れとしては以下になります。
- Apex RESTクラスを作成
- Sitesの有効なApexクラスに1のクラスを追加
- SNSでHTTP EndpointをSitesのURL(Apex REST)に設定し、Endpoint側でSubscribeする。 Endpointは下記サンプルクラスの場合はhttps://[SiteDomain]//services/apexrest/MyRestContextExampleになります。 ※HTTP Endpointに確認メッセージが送られるので、Salesforce側でデバッグするなりDBに格納するなりで メッセージ内容を取得し、メッセージ内のSubscribeURLにアクセスすると、当EndpointがSNS側に登録されるっていう流れ。
- consoleからpublish
1のクラスはこんな感じ
@RestResource(urlMapping='/MyRestContextExample/*')
global with sharing class MyRestContextExample {
@HttpPost
global static Boolean doPost() {
RestRequest req = RestContext.request;
RestResponse res = RestContext.response;
Map<String, Object> notificationParams = (Map<String, Object>)JSON.deserializeUntyped(req.requestBody.ToString());
if (String.valueOf(notificationParams.get('Type')) == 'Notification') {
if (notificationParams.containsKey('Message')) {
CallTwilio.sendSMS(String.valueOf(notificationParams.get('Message')));
}
}
system.debug(req.requestBody.ToString());
system.debug(req.headers);
system.debug(req.params);
system.debug(req.resourcePath);
return true;
}
}
public with sharing class CallTwilio {
public static void sendSMS(String sms_message) {
TwilioRestClient client = TwilioAPI.getDefaultClient();
TwilioMessage message = client.getAccount().getMessages().create(new Map<String, String>{
'To' => '+*********',
'From' => '+*********',
'Body' => sms_message
});
}
}
本当はMessageのSignatureの検証をする必要がありますが、SNSのAWSからのHttp Notificationは単純に共通鍵方式ではなく、公開鍵で検証する方式になります。が、Apexには公開鍵でverifyするメソッドがなかったので断念。
この検証をしないと、偽装されたNotificationに対してもメッセージを処理しちゃいます。ということで、何らかの対策は必要で、思いつく限りはMessageとかSubjectに自前のSignature埋め込むぐらい?
MessageIDが使えれば
- API経由でNotification
- ResponseのMessageIDをDBに格納
- 受け取ったデバイスでDBに対象MessageIDがDBに格納されているかを検証
RESTクラスを作ったら、あとはSites登録してconsoleからNotificationするだけです。最初のSubscription登録のときだけはSalesforceのデバッグを確認して、指定HTTP Endpointに対してSubscribeする必要があります。
これで、ひとつのTopicに対するPublishで特定メールアドレスにメールを送ったり、SMSを送信できます。