• 沒有找到結果。

A.8 HTTP(S)终端节点使用样例

A.8.4 示例代码

Java 语言

验证消息是否有效,其中signing_cert_url、signature是从HTTP(S)消息格式描述获取 的值,message为特定消息的签名键值。以下为示例代码,仅供参考。

private static void isMessageValid(String signing_cert_url, String signature, Map<String, String> message) { InputStream in = null;

try {

URL url = new URL(signing_cert_url);

in = url.openStream();

CertificateFactory cf = CertificateFactory.getInstance("X.509");

X509Certificate cert = (X509Certificate) cf.generateCertificate(in);

Signature sig = Signature.getInstance(cert.getSigAlgName());

sig.initVerify(cert.getPublicKey());

sig.update(buildSignMessage(message).getBytes("UTF-8"));

byte[] sigByte = Base64.getDecoder().decode(signature);

使用Java 8 版本以下的用户,可以使用第三方jar包commons-codec.jar进行Base64解码。

并将上述样例代码中的"byte[] sigByte = Base64.getDecoder().decode(signature);"调整为

"byte[] sigByte = Base64.decodeBase64(signature);"。

构建校验签名的示例代码

private static String buildSignMessage(Map<String,String> msg) { String type = msg.get("type");

String message = null;

if ("Notification".equals(type)){

message = buildNotificationMessage(msg);

} else if ("SubscriptionConfirmation".equals(type) ||

"UnsubscribeConfirmation".equals(type)){

用户指南 A 附录

message = buildSubscriptionMessage(msg);

}

return message;

}

private static String buildSubscriptionMessage(Map<String, String> msg) { String stringMessage = "message\n";

stringMessage += msg.get("message") + "\n";

stringMessage += "message_id\n";

stringMessage += msg.get("message_id") + "\n";

stringMessage += "subscribe_url\n";

stringMessage += msg.get("subscribe_url") + "\n";

stringMessage += "timestamp\n";

stringMessage += msg.get("timestamp") + "\n";

stringMessage += "topic_urn\n";

stringMessage += msg.get("topic_urn") + "\n";

stringMessage += "type\n";

stringMessage += msg.get("type") + "\n";

return stringMessage;

}

private String buildNotificationMessage(Map<String, Object> msg) {

String stringMessage = "message\n";

stringMessage += msg.get("message").toString() + "\n";

stringMessage += "message_id\n";

stringMessage += msg.get("message_id").toString() + "\n";

if (msg.get("subject") != null){

stringMessage += "subject\n";

stringMessage += msg.get("subject").toString() + "\n";

}

stringMessage += "timestamp\n";

stringMessage += msg.get("timestamp").toString() + "\n";

stringMessage += "topic_urn\n";

stringMessage += msg.get("topic_urn").toString() + "\n";

stringMessage += "type\n";

stringMessage += msg.get("type").toString() + "\n";

return stringMessage;

}

Node.js

const fs = require('fs');

const crypto = require('crypto');

const jsrsag = require('jsrsasign');

/** * 校验消息签名

* @param pemFile 签名文件存储路径(下载到本地证书文件路径) * @param signature 待验证的签名值

* @param message 待验证的消息内容

* @returns {boolean} true:签名值验证通过;false:签名值校验不通过 */function verifyMessage(pemFile, signature, message) {

const pubPem = fs.readFileSync(pemFile);

const verify = crypto.createVerify(signatureAlgorithm(pubPem));

verify.update(buildSignMessage(message));

const verifyResult = verify.verify(pubPem, signature, 'base64');

if (verifyResult) {

*/function signatureAlgorithm(pubPem) { const certObject = new jsrsag.X509();

certObject.readCertPEM(pubPem.toString());

let algorithm = certObject.getSignatureAlgorithmField();

if (algorithm.split('with').length > 1) {

algorithm = algorithm.split('with')[1] + '-' + algorithm.split('with')[0];

}

return algorithm;

}

function buildSignMessage(msg) { const type = msg.type;

let message = '';

if (type === 'Notification') {

message = buildNotificationMessage(msg);

} else if (type === 'SubscriptionConfirmation') { message = buildSubscriptionMessage(msg);

}

return message;

}

function buildNotificationMessage(msg) {

let signMessage = 'message\n' + msg.message + '\n';

signMessage += 'message_id\n' + msg.message_id + '\n';

if (msg.subject) {

signMessage += 'subject\n' + msg.subject + '\n';

}

signMessage += 'timestamp\n' + msg.timestamp + '\n';

signMessage += 'topic_urn\n' + msg.topic_urn + '\n';

signMessage += 'type\n' + msg.type + '\n';

return signMessage;

}

function buildSubscriptionMessage(msg) {

let signMessage = 'message\n' + msg.message + '\n';

signMessage += 'message_id\n' + msg.message_id + '\n';

signMessage += 'subscribe_url\n' + msg.subscribe_url + '\n';

signMessage += 'timestamp\n' + msg.timestamp + '\n';

signMessage += 'topic_urn\n' + msg.topic_urn + '\n';

signMessage += 'type\n' + msg.type + '\n';

return signMessage;

}

说明

该示例代码已在Nodejs v14.17.5版本上测试通过。

Go 语言

package demo import ( "bytes"

"crypto"

"crypto/rsa"

"crypto/x509"

"encoding/base64"

"encoding/json"

"encoding/pem"

"fmt"

"io/ioutil"

)

type Message struct {

Signature string `json:"signature"`

Subject *string `json:"subject"`

TopicUrn string `json:"topic_urn"`

MessageId string `json:"message_id"`

用户指南 A 附录

SignatureVersion string `json:"signature_version"`

Type string `json:"type"`

Message string `json:"message"`

SubscribeUrl string `json:"subscribe_url"`

UnsubscribeUrl string `json:"unsubscribe_url"`

SigningCertUrl string `json:"signing_cert_url"`

Timestamp string `json:"timestamp"`

}

func VerifyMessage(pemFile string, message string) bool { msg := Message{}

err := json.Unmarshal([]byte(message), &msg) if err != nil {

fmt.Println("Convert json to struct failed") return false

}

pemContent, err := ioutil.ReadFile(pemFile) if err != nil {

fmt.Println("Read pem file failed") return false

}

certDerblock, _ := pem.Decode(pemContent) if certDerblock == nil {

fmt.Println("Decode pem file failed") return false

}

cert, err := x509.ParseCertificate(certDerblock.Bytes) if err != nil {

fmt.Println("Parse cert failed") return false

}

msgString := buildMessage(&msg) msgHash := crypto.SHA256.New() msgHash.Write([]byte(msgString)) msgHashSum := msgHash.Sum(nil)

decodeSign, _ := base64.StdEncoding.DecodeString(msg.Signature) publicKey := cert.PublicKey.(*rsa.PublicKey)

err = rsa.VerifyPKCS1v15(publicKey, crypto.SHA256, msgHashSum, decodeSign) if err != nil {

func buildMessage(msg *Message) string { if msg.Type == "Notification" {

return buildNotificationMessage(msg)

} else if msg.Type == "SubscriptionConfirmation" || msg.Type == "UnsubscribeConfirmation" { return buildSubscriptionMessage(msg)

} return ""

}

func buildNotificationMessage(msg *Message) string { buf := bytes.Buffer{}

buf.WriteString("message\n" + msg.Message + "\n") buf.WriteString("message_id\n" + msg.MessageId + "\n") // msg中存在Subject字段不存在的场景,需要特殊处理 if msg.Subject != nil {

buf.WriteString("subject\n" + *msg.Subject + "\n") }

buf.WriteString("timestamp\n" + msg.Timestamp + "\n") buf.WriteString("topic_urn\n" + msg.TopicUrn + "\n")

buf.WriteString("type\n" + msg.Type + "\n") return buf.String()

}

func buildSubscriptionMessage(msg *Message) string { buf := bytes.Buffer{}

buf.WriteString("message\n" + msg.Message + "\n") buf.WriteString("message_id\n" + msg.MessageId + "\n") buf.WriteString("subscribe_url\n" + msg.SubscribeUrl + "\n") buf.WriteString("timestamp\n" + msg.Timestamp + "\n") buf.WriteString("topic_urn\n" + msg.TopicUrn + "\n") buf.WriteString("type\n" + msg.Type + "\n") return buf.String()

}

说明

该示例代码已在go 1.15版本上测试通过。

用户指南 A 附录

B 修订记录

版本日期 变更说明

2020-09-30 第十八次正式发布。

本次变更说明如下:

整体优化文档。

2020-01-20 第十七次正式发布。

变更说明:

“权限管理”章节删除IAM相关概念及操作内容,修 改为链接至IAM手册。

2019-07-05 第十六次正式发布。

变更说明:

新增“权限管理”章节。

2019-03-30 第十五次正式发布。

变更说明:

修改标签键的校验规则。

2018-11-30 第十四次正式发布。

变更说明:

● 新增“移动推送管理”章节

● 新增应用协议 2018-07-18 第十三次正式发布。

变更说明:

● 新增常见问题“短信发送失败,如何查看发送失败 原因?”

● 更新截图

版本日期 变更说明

2018-07-02 第十二次正式发布。

变更说明:

● 将FunctionGraph协议修改为 FunctionGraph(工 作流)协议

● 将FunctionStage协议修改为FunctionGraph(函 数)协议

● 新增设置主题标签

● 更新部分截图 2018-04-30 第十一次正式发布。

修改:

● 海外短信支持的国家和地区

● 短信签名、短信模板和发送短信章节截图刷新

● 修改“记录消息通知服务”章节 2018-01-30 第十次正式发布。

修改: 2017-10-30 第九次正式发布。

新增:

● FunctionGraph订阅协议。

● DMS订阅协议。

● 发送短信功能。

● 短信配置事件功能。

2017-8-18 第八次正式发布。

修改:

所有页面截图。

新增:

FunctionStage订阅协议。

2017-06-30 第七次正式发布。

新增:

创建短信签名。

用户指南 B 修订记录

版本日期 变更说明

2017-05-30 第六次正式发布。

新增:

● 删除创建主题页面的发布消息按钮。

● 输入主题别名不允许换行。

2017-3-13 第五次发布。

新增:

修改主题简介。

2016-11-30 第四次发布。

新增:

高级策略配置。

2016-10-29 第三次正式发布。

新增:

对接云审计服务记录资源操作。

2016-09-30 第二次正式发布。

新增:

修改主题策略。

2016-08-25 第一次正式发布。

相關文件