如何确认来自亚马逊SNS的订阅请求HTTP

问题描述 投票:0回答:6

我一直在网上搜索,但没有给出明确的答案来确认亚马逊 SNS 的订阅请求。我已经将订阅从亚马逊控制台发送到我的网站,但接下来该怎么办?我使用 amazon EC2 作为我的 PHP 服务器。

amazon-web-services amazon-sns
6个回答
25
投票

在通过 AWS 管理控制台配置 HTTP/HTTPS 终端节点订阅之前,您需要确保 PHP 网站的 HTTP 或 HTTPS 终端节点能够处理 Amazon SNS 生成的 HTTP POST 请求。 SNS 消息有多种类型:SubscriptionConfirmation、Notification 和 UnsubscribeConfirmation。您的 PHP 代码需要从请求中获取标头 x-amz-sns-message-type 并根据消息类型对其进行处理。对于 SubscriptionConfirmation 消息,您的 PHP 应用程序需要处理 POST 消息正文,这是一个 JSON 文档。为了订阅主题,您的 PHP 代码需要访问 JSON 正文中指定的“SubscriberURL”。或者,您应该在订阅主题之前验证签名以确保消息的真实性。

您可以在 AWS 文档上找到更多详细信息:http://docs.aws.amazon.com/sns/latest/dg/SendMessageToHttp.html


24
投票

这是一个确认 SNS 订阅的 Express 应用程序 (Node.js):

const express = require('express')
const request = require('request')
// parse urlencoded request bodies into req.body
const bodyParser = require('body-parser')
const app = express()
const port = 8080

app.use(bodyParser.urlencoded({ extended: false }))
app.use(bodyParser.json())

app.post('/', (req, res) => {
  let body = ''

  req.on('data', (chunk) => {
    body += chunk.toString()
  })
  
  req.on('end', () => {
    let payload = JSON.parse(body)
    
    if (payload.Type === 'SubscriptionConfirmation') {
      const promise = new Promise((resolve, reject) => {
        const url = payload.SubscribeURL
        
        request(url, (error, response) => {
          if (!error && response.statusCode == 200) {
            console.log('Yess! We have accepted the confirmation from AWS')
            return resolve()
          } else {
            return reject()
          }
        })
      })

      promise.then(() => {
        res.end("ok")
      })
    }
  })
})

app.listen(port, () => console.log('Example app listening on port ' + port + '!'))

要使用它,需要安装所需的软件包:

yarn add express request body-parser

一旦您确认订阅,AWS 将向服务器发送一个

POST
请求,其中包含以下内容:

{
  "Type": "SubscriptionConfirmation",
  "MessageId": "XXXXXXXX-1ee3-4de3-9c69-XXXXXXXXXXXX",
  "Token": "SECRET_TOKEN",
  "TopicArn": "arn:aws:sns:us-west-2:XXXXXXXXXXXX:ses-test",
  "Message": "You have chosen to subscribe to the topic arn:aws:sns:us-west-2:XXXXXXXXXXXX:ses-test. To confirm the subscription, visit the SubscribeURL included in this message.",
  "SubscribeURL": "https://sns.us-west-2.amazonaws.com/?Action=ConfirmSubscription&TopicArn=arn:aws:sns:us-west-2:XXXXXXXXXXXX:ses-test&Token=SECRET_TOKEN",
  "Timestamp": "2018-11-21T19:48:08.170Z",
  "SignatureVersion": "1",
  "Signature": "SECRET",
  "SigningCertURL": "https://sns.us-west-2.amazonaws.com/SimpleNotificationService-XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX.pem"
}

有效负载包含服务器请求的

SubscribeURL


13
投票

您指定的端点将从 AWS SNS 端点验证服务获取数据,同一端点将用于验证端点并从 aws 获取通知,

只需将 AWS SNS 发送的输入转储到一个文本文件中,例如,

$json_write_to_text = json_decode(file_get_contents("php://input"));

您将找到 AWS SNS 发送的所有数据,但只需找到

SubscriptionUrl
(这将特定于具有有效令牌的端点),在浏览器中打开它,您将具有 SubscriptionConfirmation 状态。就是这样

享受吧。


2
投票

带有注解的Spring云SNS订阅

Spring Cloud AWS 支持自动确认订阅者,只需添加此注解“@NotificationSubscriptionMapping”即可

@Controller
@RequestMapping("/topicName")
public class NotificationTestController {

    @NotificationSubscriptionMapping
    public void handleSubscriptionMessage(NotificationStatus status) throws IOException {
        //We subscribe to start receive the message
        status.confirmSubscription();
    }

    @NotificationMessageMapping
    public void handleNotificationMessage(@NotificationSubject String subject, @NotificationMessage String message) {
        // ...
    }

    @NotificationUnsubscribeConfirmationMapping
    public void handleUnsubscribeMessage(NotificationStatus status) {
        //e.g. the client has been unsubscribed and we want to "re-subscribe"
        status.confirmSubscription();
    }
}

http://cloud.spring.io/spring-cloud-aws/spring-cloud-aws.html#_sns_support


0
投票

我使用 NodeJS 后端解决了这个问题。假设你在 HapiJS 中有一个这样的 API(好吧,你可以拥有其他技术并不重要)

{
    method: 'POST',
    path: '/hello',
    handler: ( request, reply ) => {

        reply( Hello.print(request.payload) );
    },
    config: {
        tags: ['api']
    }
}

只需将您收到的有效负载传递给您的业务逻辑即可。

业务逻辑流程是这样的

    'use strict';
    const request = require('request');

    exports.print = (payload) => {

    payload = JSON.parse(payload);
    if(payload.Type === 'SubscriptionConfirmation'){

        return new Promise((resolve, reject) => {
            const url = payload.SubscribeURL;
            request(url, (error, response) => {

                if (!error && response.statusCode == 200) {
                    console.log('Yess! We have accepted the confirmation from AWS');
                    return resolve();
                }
                else 
                    return reject();
            });
        });
    }

我正在使用 NPM 的请求模块来自动接受此类请求。

另一种方法是打印

payload
的内容,然后单击
payload.SubscribeURL
中给出的 URL。

AWS 接受后,您可以在订阅页面上检查确认信息,其中

Subscription ARN
将从
Pending Confirmation
更改为包含您的主题名称的复杂名称兼 SHA。


0
投票

基本上,为了进行测试,我使用 ngrok 服务器向 Python Flask 服务器发出请求,并将 HTTPS 传输类型订阅添加到 AWS SNS 主题。在这种情况下,对于订阅确认,它触发了端点,并且该端点保存 SubscribeURL 值。您需要将该值放入下面 UI 的确认订阅示例中。

带有订阅功能的 aws 的 Ui [为了确认订阅,请选择该订阅并将 SubscribeURL 值放入确认订阅中][1] [1]:https://i.sstatic.net/TpBnYndJ.png

© www.soinside.com 2019 - 2024. All rights reserved.