使用GO代码实现 百度联盟媒体平台的DSA签名

Posted 年少~年

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了使用GO代码实现 百度联盟媒体平台的DSA签名相关的知识,希望对你有一定的参考价值。

1. AccessKey
百度百度联盟将为每一个会员账号分配一个16 位字母数字组成的字符串,作为账号的
唯一标识。由百度联盟商务合作经理于线下发给会员。
2. IP 白名单
百度联盟会员需要线下向百度百度联盟平台提供欲访问API 的 IP 地址列表。目前不支
持 IP 段。
3. DSA 私钥公钥对
会员需要自己生成 PEM 格式的 DSA 私钥公钥对,并妥善保管好私钥,同时将公钥
线下提供给百度百度联盟平台。

生成方法:
1. 生成随机参数
openssl dsaparam -out dsaparam.pem 1024
2. 生成 DSA 私钥 privkey.pem
openssl gendsa -out privkey.pem dsaparam.pem
3. 生成公钥 pubkey.pem
openssl dsa -in privkey.pem -pubout -out pubkey.pem

4. API 的 HTTP 请求头
为了验证平台身份,需要在HTTP Header 中额外增加以下两项内容:
4. x-ub-authorization: 用户信息+请求信息的签名(签名算法见下一小结),
格式为:$AccessKey: $Signature。
5. x-ub-date: 请求的时间,格式为Unix-Time 时间戳

5. 签名算法
需要将以下内容用“\\n”连接起来,作为待签名的数据。然后将待签名的数据用DSA
私钥通过SHA1 算法加密编码,加密后的结果(字节数组)使用BASE64 进行编码,
作为签名使用。

1. 用户的AccessKey
2. HTTP Method(GET、POST、PUT 等),见接口定义中的HTTP 方法
3. 请求的资源的url及query参数(不包含协议及Host 部分),见接口定义中的URL
4. x-ub-date 时间戳
例如:

11. GET 请求
// 用户的Access Key 为 ABCDEFGHIJKLMN12
// 当前的 unix 时间为 1387106898
// GET /union/11.0/apps?page=1&count=10
==== 待签名的内容,不包含本行内容 ====
"ABCDEFGHIJKLMN12\\n"
+ "GET\\n"
+ 
"/ssp/1/sspservice/app/app-report/get-app-report?begindate=20190901&
enddate=20190902\\n"
+ "1387106898\\n"
+ "\\n"
+ ""

私钥文件:

-----BEGIN DSA PRIVATE KEY-----
MIIBvAIBAAKBgQD9f1OBHXUSKVLfSpwu7OTn9hG3UjzvRADDHj+123456789
+1k9jVj6v8X1ujD2y5tVbNeBO4AdNG/123456789+gEexAiwk+7qdf+t8Yb
+DtX58aophUPBPuD9tPFHsMCNVQTWhaRMvZ1864rYdcq7/IiAxmd0UgBxwIVAJdg
UI8VIwvMspK5gqLrhAvwWBz1AoGBAPfhoIXWmz3ey7yrXDa4V7l5lK+7+jrqgvlX
TAs9B4JnUVlXjrrUWU/mcQcQgYC0SRZxI+12345678991233333
rh4rs6Z1kW6jfwv6ITVi8ftiegEkO8yk8b6oUZCJqIPf4VrlnwaSi2ZegHtVJWQB
QQv+z0kqAoGBAMi2XZH2ebKSwLuRdWnWJYug/12345677898989/M+MhQLK
V6+foRix6Z5nsYLZI0eLcTLEcE+kfiNuWegU7gca0chHM/Kc2TgO1U8HSsSsoFgt
GCtN+66777899454545566565/dSKihFAhRHC4BI
2244+aFh/123456789998878787==
-----END DSA PRIVATE KEY-----

php生成签名方法:

<?php

class UbapiClient 
    private $host = "https://ubapi.baidu.com";
    private $private_key;
    private $accessKey;

    /**
     * @param $privkeyPath 私钥的文件路径
     * @param $accessKey access key
     * @return UbapiClient
     */
    function __construct($privkeyPath, $accessKey) 

        // 1. read private key
        $fp = fopen($privkeyPath, "r");
        $cert = fread($fp, 8192);
        fclose($fp);
        $this->private_key = openssl_get_privatekey($cert);

        $this->accessKey = $accessKey;

    

    /**
     * 发起GET请求
     * @param @uri 例如 /ssp/1/report?date=20151127
     * @return (状态码,响应的body内容)
     */
    function doGet($uri) 
        $method = "GET";
        $contentType = "";
        $bodyMd5 = "";
        $timestamp = time();

        $message = $this->accessKey . "\\n" . $method . "\\n" . $uri . "\\n" . $timestamp . "\\n" . $contentType . "\\n" . $bodyMd5;

        $binary_signature = "";
        openssl_sign($message, $binary_signature, $this->private_key, OPENSSL_ALGO_DSS1);
        $signature = base64_encode($binary_signature);
        $headers = array(
            $method . $uri . " HTTP/1.0",
            "x-ub-date" . ": " .  $timestamp, 
            "x-ub-authorization" . ": " .  $this->accessKey . ":" . $signature,
        );

        $client = curl_init();
        curl_setopt($client, CURLOPT_URL, $this->host . $uri);
        curl_setopt($client, CURLOPT_HTTPHEADER, $headers);
        curl_setopt($client, CURLOPT_RETURNTRANSFER, true);

        $result = curl_exec($client);
        $status= curl_getinfo($client, CURLINFO_HTTP_CODE);
        curl_close($client);
        return array($status, $result, );
    

    /**
     * 发起POST请求
     * @param @uri 例如 /ssp/1/report?date=20151127
     * @param $contentType 例如 application/json
     * @param $body 请求的body内容
     * @return (状态码,响应的body内容)
     */
    function doPost($uri, $contentType, $body) 
        $method = "POST";
        $bodyMd5 = md5($body);
        $timestamp = time();

        $message = $this->accessKey . "\\n" . $method . "\\n" . $uri . "\\n" . $timestamp . "\\n" . $contentType . "\\n" . $bodyMd5;

        $binary_signature = "";
        openssl_sign($message, $binary_signature, $this->private_key, OPENSSL_ALGO_DSS1);
        $signature = base64_encode($binary_signature);
        $headers = array(
            $method . $uri . " HTTP/1.0",
            "Content-type: " . $contentType,
            "Content-Length: " . strlen($body),
            "x-ub-date" . ": " .  $timestamp, 
            "x-ub-authorization" . ": " .  $this->accessKey . ":" . $signature,
        );

        $client = curl_init();
        curl_setopt($client, CURLOPT_URL, $this->host . $uri);
        curl_setopt($client, CURLOPT_HTTPHEADER, $headers);
        curl_setopt($client, CURLOPT_RETURNTRANSFER, true);

        curl_setopt($client, CURLOPT_POST, 1); 
        curl_setopt($client, CURLOPT_POSTFIELDS, $body); 

        $result = curl_exec($client);
        $status= curl_getinfo($client, CURLINFO_HTTP_CODE);
        curl_close($client);
        return array($status, $result, );
    



// init
// 参数:private key + access token
$client = new UbapiClient("privkey.pem", "123456789FORTEST");

// GET example
$uri = "/ssp/1/sspservice/report/report/get-reports?dimensions=day,appId,appName&metrics=view,click,income&begin=20150810&end=20150820";
$result = $client->doGet($uri);
echo "\\nGET\\n";
echo "status: $result[0]\\n";
echo "result: $result[1]\\n";

// POST example
$uri = "/ssp/1/sspservice/adposition/app/adPositions/status";
$body = '"ids":[2076803,2076804], "status":"DELETED"';
$result = $client->doPost($uri, "application/json", $body);
echo "\\nPOST\\n";
echo "status: $result[0]\\n";
echo "result: $result[1]\\n";
?>

GO生成签名的方法

import (
	"crypto/dsa"
	"crypto/rand"
	"crypto/sha1"
	"encoding/asn1"
	"encoding/base64"
	"encoding/json"
	"golang.org/x/crypto/ssh"
	"io/ioutil"
	"math/big"
	"net/http"
	"strconv"
	"time"
)

const BaiDuUrlPrefix = "https://ubapi.baidu.com"
const BaiDuAccessKey = "123456789"
const BaiduPrivKem = "-----BEGIN DSA PRIVATE KEY-----\\nMIIBvAIBAAKBgQCo20fromvK7o+SF/123456789OK9Le0RJyieD\\nWLsPPWJJ+QFyia90Uaj123456789zkuC+1lM\\nwtX3lxnzjKpKlwlqhD/lkf8E3AdCZW/1234567\\niOPepuvmWrFAGQlrX3EL636hAoGAb7XH6Yr/74+123456789\\n9mQkT2b6wRix123456sOmxxriTjJZBrXVpXdpPrGX7/ggGR1nsg3C2f/K\\n1wUPs8qqUqh412347FI0mN+U7CghJ//123456789\\nQOZ0OvcCgYEAg6/yDeATH/123456789/4TGCFGMD\\nCTPZ+123456789/FJ/voeEClNOPI48/dQ90coGTVfx8ci\\nv6oJQ+u2VdaINgrk42UHRu6bYqqhSBFIl/12345678999\\nA4Htul7UGu0/3qV8r75boQ==\\n-----END DSA PRIVATE KEY-----"



// 生成签名
func GetSignature(x_ub_date int64, method string, query string) string 
	//需要将以下内容用“\\n”连接起来,作为待签名的数据。然后将待签名的数据用DSA 私钥通过SHA1 算法加密编码,加密后的结果(字节数组)使用BASE64 进行编码,
	//作为签名使用。
	//1. 用户的AccessKey
	//2. HTTP Method(GET、POST、PUT 等),见接口定义中的HTTP 方法
	//3. 请求的资源的url及query参数(不包含协议及Host 部分),见接口定义中的URL
	//4. x-ub-date 时间戳

	//

	accessKey := BaiDuAccessKey
    // int64转str
	x_ub_date_str := strconv.FormatInt(x_ub_date, 10)
	str := accessKey + "\\n" + method + "\\n" + query + "\\n" +  x_ub_date_str + "\\n" + "\\n" + ""


	sign, err := Sign(str, BaiduPrivKem)
	if err != nil 
		logx.Error("sign error:", err.Error())
	
	logx.Info("sign:",sign)
	return sign


type dsaSignature struct 
	R *big.Int
	S *big.Int


func Sign(originalData string, pemData string) (string, error) 

	p, _ := ssh.ParseRawPrivateKey([]byte(pemData))
	pp := p.(*dsa.PrivateKey)

	h := sha1.New()
	h.Write([]byte(originalData))
	r, s, err := dsa.Sign(rand.Reader, pp, h.Sum(nil))
	if err != nil 
		logx.Error("ssss err:",err.Error())
		return "nil", err
	
	sig := dsaSignaturer, s
	b, err := asn1.Marshal(sig)
	if err != nil 
		logx.Error("aaaaa err:",err.Error())
		return "nil", err
	

	return base64.StdEncoding.EncodeToString(b), err

个人捣鼓的小程序,欢迎多提提意见:

以上是关于使用GO代码实现 百度联盟媒体平台的DSA签名的主要内容,如果未能解决你的问题,请参考以下文章

python实现DSA签名数字证书

验证openssl c ++中的签名,该签名由JAVA DSA签名?

起点联盟模式系统开发详解

Go-ecc数字签名详解与代码

百度博客如何做广告联盟?怎么赚钱?

好课分享: Go语言实战流媒体视频网站,高效学习Go高性能开发 百度云