go执行java -jar 完成DSA私钥解析并签名

        起因,最近使用go对接百度联盟api需要使用到DSA私钥完成签名过程,在百度提供的代码示例里面没有go代码的支持,示例中仅有php、python2和3、java的代码,网上找了半天发现go中对DSA私钥解析支持不友好,然后决定使用在java中完成签名计算过程,生成可执行jar后由外部传入参数获取签名数据。

百度联盟api文档说明:

1)权限开通后,登录百度联盟媒体平台(union.baidu.com),在【账户管理 – API 管理】模块查询 AccessKey;2)自行生成 PEM 格式的 DSA 私钥公钥对,并妥善保管私钥公钥,具体生成方式如下:
1. ① 生成随机参数
2. openssl dsaparam -out dsaparam.pem 1024
3. ② 生成 DSA 私钥 privkey.pem
4. openssl gendsa -out privkey.pem dsaparam.pem
5. ③ 生成公钥 pubkey.pem
6. openssl dsa -in privkey.pem -pubout -out pubkey.pem3)按照以下说明生成签名,并以此作为请求字段调用 API:
1. 需要将:
2. ① 用户的 AccessKey
3. ② HTTP Method(GET,POST,PUT 等),见接口定义中的 HTTP 方法
4. ③ 请求的资源的 url 及 query 参数(不包含协议及 Host 部分),见接口定义中的 URL 
5. ④ x-ub-date 时间戳
6. ⑤ ContentType 如:application/json
7. ⑥ body 的 32 位 MD5 编码串
8. // 注:GET 请求无 5,6
9. 用“\n”连接起来,作为待签名的数据。
10. 然后将待签名的数据用 DSA 私钥通过 SHA1 算法加密编码,加密后的结果(字节数组)使用 BASE64 进行编码,作为签名使用。
11. 
12. 示例:
13.
14. POST 请求
15. // 用户的 AccessKey 为 6SL21N4H3J9FE70ZXXXXXXXXXXXXXXXX
16. // 当前的 unix 时间为 16183682792
17. // POST /ssp/1/sspservice/appadpos/app/adpos/create
18. ==== 待签名的内容,不包含本行内容 ====
19. "6SL21N4H3J9FE70ZXXXXXXXXXXXXXXXX\n"
20. + "POST\n"
21. + "/ssp/1/sspservice/appadpos/app/adpos/create\n"
22. + "16183682792\n"
23. + "application/json\n" 
24. + "b6cc88bb12023b96917f3a057a5c67b7"
25. GET 请求
26. // 用户的 AccessKey 为 6SL21N4H3J9FE70ZXXXXXXXXXXXXXXXX
27. // 当前的 unix 时间为 16183682792
28. // GET /union/11.0/apps?page=1&count=10
29. ==== 待签名的内容,不包含本行内容 ====
30. "6SL21N4H3J9FE70ZXXXXXXXXXXXXXXXX\n"
31. + "GET\n"
32. + "/union/11.0/apps?page=1&count=10\n"
33. + "16183682792\n"
34. + "\n" 
35. + ""
36. ==== 签名内容结束,注意,不是以\n 结尾 ====4)每次请求时,需要在 HTTP Header 中额外增加以下两项内容(必填):
l x-ub-authorization:用户信息+请求信息的签名;格式为:${AccessKey}: ${Signature};
l x-ub-date:请求的时间戳,精确到秒或毫秒。

java代码:

        main方法

import com.google.gson.Gson;
import com.google.gson.JsonObject;
import com.google.gson.reflect.TypeToken;
import org.bouncycastle.crypto.digests.MD5Digest;
import org.bouncycastle.util.encoders.Base64;
import org.bouncycastle.util.encoders.Hex;import java.lang.reflect.Type;
import java.security.PrivateKey;
import java.util.List;public class App {public static void main(String[] args) {if (args == null || args.length != 2) {throw new RuntimeException("params nums error");}String dsaPrivateKey = args[0];// post arr := []string{AccessKey, Method, Path, Unix, ContentType, string(jsonData)}// get arr := []string{AccessKey, Method, Path, Unix}String jsonArray = args[1];Gson gson = new Gson();Type listType = new TypeToken<List<String>>() {}.getType();List<String> stringList = gson.fromJson(jsonArray, listType);if (stringList.size() == 6) {// postString body = stringList.get(stringList.size() - 1);// 取出最后一位body入参JsonObject jsonObject = gson.fromJson(body, JsonObject.class);byte[] content = jsonObject.toString().getBytes();MD5Digest digest = new MD5Digest();digest.update(content, 0, content.length);byte[] digestBytes = new byte[digest.getDigestSize()];digest.doFinal(digestBytes, 0);stringList.set(stringList.size() - 1, new String(Hex.encode(digestBytes)));} else if (stringList.size() == 4) {// get// empty ContentTypestringList.add("");// empty content md5stringList.add("");} else {System.out.println();}// 待签名数据String stringTobeSigned = String.join("\n", stringList);PrivateKey privateKey = SignatureUtils.parsePemPrivateKey(dsaPrivateKey);byte[] signatureBytes = SignatureUtils.signMessage(privateKey, stringTobeSigned.getBytes());String signature = new String(Base64.encode(signatureBytes));System.out.print(stringList.get(0) + ":" + signature);}
}

        签名工具类SignatureUtils :

import org.bouncycastle.jce.provider.BouncyCastleProvider;
import org.bouncycastle.openssl.PEMReader;import java.io.IOException;
import java.io.StringReader;
import java.security.KeyPair;
import java.security.PrivateKey;
import java.security.Security;
import java.security.Signature;/*** 签名相关的工具类** @version 1.0.0*/
public class SignatureUtils {static {if (Security.getProvider("BC") == null) {Security.addProvider(new BouncyCastleProvider());}}/*** 读取privateKey** @param pemKey* @return*/public static PrivateKey parsePemPrivateKey(String pemKey) {PEMReader reader = new PEMReader(new StringReader(pemKey));Object key;try {key = reader.readObject();reader.close();} catch (IOException e) {throw new RuntimeException("read pubKey error, pemKey: " + pemKey);}if (key instanceof KeyPair) {return ((KeyPair) key).getPrivate();}throw new RuntimeException("not a private key, pemKey: " + pemKey);}/*** 签名信息** @param privateKey* @param message* @return*/public static byte[] signMessage(PrivateKey privateKey, byte[] message) {Signature dsa;try {dsa = Signature.getInstance("SHA1withDSA", "SUN");dsa.initSign(privateKey);dsa.update(message);return dsa.sign();} catch (Exception e) {throw new RuntimeException("sign error, stack trace: " + e);}}}

        pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>xxx.xxx</groupId><artifactId>baiduDsaParse</artifactId><version>1.0-SNAPSHOT</version><packaging>jar</packaging><name>baiduDsaParse</name><properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding></properties><build><plugins><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-assembly-plugin</artifactId><version>3.3.0</version><configuration><descriptorRefs><descriptorRef>jar-with-dependencies</descriptorRef></descriptorRefs><archive><manifest><mainClass>xxx.xxx.App</mainClass> <!-- 指定你的主类 --></manifest></archive></configuration><executions><execution><id>make-assembly</id><phase>package</phase><goals><goal>single</goal></goals></execution></executions></plugin><plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><configuration><source>8</source><target>8</target></configuration></plugin></plugins></build><dependencies><dependency><groupId>org.bouncycastle</groupId><artifactId>bcprov-jdk16</artifactId><version>1.46</version></dependency><dependency><groupId>com.google.code.gson</groupId><artifactId>gson</artifactId><version>2.8.5</version></dependency></dependencies></project>

go代码:

        执行jar方法

package xxximport ("fmt""os/exec"
)type ThisSoft struct {
}func (thisSoft *ThisSoft) RunCommand(dsaPrivateKey, params string) (string, error) {// 这里要改为服务器的资源路径filePath := "D:/goProjects/server/lib/baiduDsaParse-1.0-SNAPSHOT.jar"// 要执行的命令cmd := exec.Command("java", "-jar", filePath, dsaPrivateKey, params)outByte, err := cmd.CombinedOutput()if err != nil {fmt.Println("命令执行出错:", err)return "", err}return string(outByte), nil
}

api调用:

func (thisMethod *ThisBaiduApi) MediumGetPage(AccessKey string, dsaPrivateKey string, request *MediumGetPageRequest) (*MediumPageResponse, error) {// 将请求参数序列化为 JSONjsonData, err := json.Marshal(request)if err != nil {return nil, err}// 发送 HTTP 请求Path := "/ssp/1/sspservice/medium/app-manage/page-sdk-app"Method := "POST"client := &http.Client{}fmt.Println("request json:" + string(jsonData))req, err := http.NewRequest(Method, BASE_URL+Path, bytes.NewBuffer(jsonData))if err != nil {return nil, err}// 时间戳Unix := strconv.FormatInt(time.Now().Unix(), 10)ContentType := "application/json"arr := []string{AccessKey, Method, Path, Unix, ContentType, string(jsonData)}params, err := json.Marshal(arr)if err != nil {return nil, err}// 执行jar获取签名,私钥和参数传入jar中计算出签名// 这里把参入传过去计算是为了防止计算签名是json序列化工具不同引起错误token, err := soft.RunCommand(dsaPrivateKey, string(params))if err != nil {return nil, errors.New("generate auth fail")}// 设置请求头req.Header.Set("Content-Type", ContentType)req.Header.Set("x-ub-authorization", token)req.Header.Set("x-ub-date", Unix)resp, err := client.Do(req)if err != nil {return nil, err}defer resp.Body.Close()if resp.StatusCode != 200 {return nil, errors.New("resp error, Status=" + resp.Status)}// 解析返回值var response MediumPageResponseif err := json.NewDecoder(resp.Body).Decode(&response); err != nil {return nil, err}return &response, nil
}

 如果有go原生的支持请留言告诉我,十分感谢!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/23076.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【亲测有效】百度Ueditor富文本编辑器添加插入视频、视频不显示、和插入视频后二次编辑视频标签不显示,显示成img标签,二次保存视频被替换问题,解决方案

【亲测有效】项目使用百度Ueditor富文本编辑器上传视频相关操作问题 1.百度Ueditor富文本编辑器添加插入视频、视频不显示 2.百度Ueditor富文本编辑器插入视频后二次编辑视频标签不显示&#xff0c;在编辑器内显示成img标签&#xff0c;二次保存视频被替换问题 问题1&#xff1…

RT-Thread+STM32L475VET6——USB鼠标模拟

文章目录 前言一、板载资源二、具体步骤1.配置icm20608传感器2.打开CubeMX进行USB配置3. 配置USB3.1 打开USB驱动3.2 声明USB3.3 剪切stm32xxxx_hal_msp.c中的void HAL_PCD_MspInit(PCD_HandleTypeDef* hpcd)和void HAL_PCD_MspDeInit(PCD_HandleTypeDef* hpcd)函数至board.c3.…

Vue 中单向数据流原则

做一个 ElementUI 弹框组件的二次封装 效果如下: 点击取消按钮发现弹出如下报错信息 : [Vue warn]: Avoid mutating a prop directly since the value will be overwritten whenever the parent component re-renders. Instead, use a data or computed property based on the …

前后端分离系统架构:基于Spring Boot的最佳实践

前后端分离系统架构图描绘了一个基于Springboot的前端后台分离的系统架构。它强调了前端&#xff08;客户端&#xff09;与远程&#xff08;服务器&#xff09;的解耦&#xff0c;通过API接口进行交互&#xff0c;分别独立开发和部署。 前后端分离系统架构图 从上到下&#xff…

Neo4j使用neo4j-admin导入csv数据方法

在neo4j desktop里创建project&#xff0c;创建dbms&#xff0c;创建database。 将csv文件放入如下import路径中&#xff0c;然后就可以使用相对路径来使用csv了。 在neo4j desktop中打开Terminal 键入导入数据语句&#xff1a; neo4j-admin database import full --nodes&qu…

【Transformer架构】

目录 一、Transformer介绍 1.1 Transformer的诞生 1.2 什么是Transformer 1.3 Transformer的优势 1.4 Transformer的市场 二、Transformer架构 2.1 Transformer模型的作用 2.2 Transformer总体架构图 2.2.1 Transformer总体架构 2.2.2 输入部分 2.2.3 输出部分 2.2.…

设计模式-组合模式、模板模式

组合模式 定义 将对象组合成树形结构以表示"部分-整体"的层次结构&#xff0c;组合模式使得用户对单个对象和组合对象的使用具有一致性&#xff1b; 组合模式实现的最关键的地方是-简单对象和复合对象必须实现相同的接口。这就是组合模式能够将组合对象和简单对象进…

Spring Boot 概要(官网文档解读)

Spring Boot 概述 Spring Boot 是一个高效构建 Spring 生产级应用的脚手架工具&#xff0c;它简化了基于 Spring 框架的开发过程。 Spring Boot 也是一个“构件组装门户”&#xff0c;何为构件组装门户呢&#xff1f;所谓的“构件组装门户”指的是一个对外提供的Web平台&#x…

SkyWalking集成Kafka实现日志异步采集经验总结

SkyWalking日志异步采集架构 【重点知识】 1、【Agent】kafka-reporter-plugin-x.x.x.jar包放plugins目录后必走kafka&#xff08;kafka没有正确配置就会报错&#xff09; 2、【Agent】异步如不开启数据压缩&#xff0c;日志数据较大&#xff0c;pod多、业务大时容易造成网络…

2025前端框架最新组件解析与实战技巧:Vue与React的革新之路

作者&#xff1a;飞天大河豚 引言 2025年的前端开发领域&#xff0c;Vue与React依然是开发者最青睐的框架。随着Vue 3的全面普及和React 18的持续优化&#xff0c;两大框架在组件化开发、性能优化、工程化支持等方面均有显著突破。本文将从最新组件特性、使用场景和编码技巧三…

Orange 单体架构 - 快速启动

1 后端服务 1.1 基础设施 组件说明版本MySQLMySQL数据库服务5.7/8JavaJava17redis-stackRedis向量数据库最新版本Node安装Node22.11.0 1.2 orange-dependencies-parent 项目Maven依赖版本管理 1.2.1 项目克隆 GitHub git clone https://github.com/hengzq/orange-depende…

Layer2 扩容解决方案详解

Layer2 扩容解决方案详解 &#x1f504; 1. Layer2 基础概念 1.1 什么是 Layer2&#xff1f; Layer2 是建立在以太坊主网&#xff08;Layer1&#xff09;之上的扩容解决方案&#xff0c;它&#xff1a; 继承以太坊的安全性提供更高的交易吞吐量降低交易费用保持去中心化特性…

小智机器人CMakeLists编译文件解析

编译完成后&#xff0c;成功烧录&#xff01; 这段代码是一个CMake脚本&#xff0c;用于配置和构建一个嵌入式项目&#xff0c;特别是针对ESP32系列芯片的项目。CMake是一个跨平台的构建系统&#xff0c;用于管理项目的编译过程。 set(SOURCES "audio_codecs/audio_code…

银河麒麟系统安装mysql5.7【亲测可行】

一、安装环境 cpu&#xff1a;I5-10代&#xff1b; 主板&#xff1a;华硕&#xff1b; OS&#xff1a;银河麒麟V10&#xff08;SP1&#xff09;未激活 架构&#xff1a;Linux 5.10.0-9-generic x86_64 GNU/Linux mysql版本&#xff1a;mysql-5.7.34-linux-glibc2.12-x86_64.ta…

【Linux】动静态库

目录 站在库提供者的角度 静态库 制作静态库 静态库的内容 发布静态库 用户使用静态库 找头文件 找库文件 动态库 制作动态库 动态库报错 动态库是怎么被加载的&#xff1f; 地址相关问题 程序加载前的地址 程序加载后的地址 如何执行第一条指令&#xff1f; …

500字理透react的hook闭包问题

在react中hook的闭包问题很容易在不经意间犯错&#xff0c;项目写大了之后更是难以找到到底是哪里出了问题。 为什么会出现闭包问题 出现闭包问题的原因就是函数中操作的变量不是最新的变量&#xff0c;什么意思呢&#xff0c;我们知道函数组件每次刷新都是重新运行一次函数&…

Unity Shader Graph 2D - 一个简单的魔法阵激活效果

前言 在魔幻类游戏里通常会有魔法阵的存在,而当某个机关被触发或者某个剧情被触发时,需要对魔法阵进行激活,这个时候就需要一个魔法阵的激活效果来让这个游戏的这一时刻的交互性更强,生动性更强,本文将用一种十分简单的方式来实现一个魔法阵的激活效果。 创建一个…

C++ 类和对象(友元、内部类、匿名对像)

目录 一、前言 二、正文 1.友元 1.1友元函数的使用 1.1.1外部友元函数可访问类的私有成员&#xff0c;友员函数仅仅是一种声明&#xff0c;他不是类的成员函数。 1.1.2一个函数可以是多个类的友元函数 2.友元类的使用 2.1什么是友元类 2.2 友元类的关系是单向的&#x…

Docker Network

1.简介 容器之间的通讯时通过网桥通讯的&#xff0c;跨主机通讯可以使用flannel进行通讯 那么为什么主机可以访问到虚拟机内部呢&#xff1f;因为VMware虚拟出一个虚拟的网卡&#xff0c;而这个虚拟网卡和主机在同一个局域网下 NAT是映射一个虚拟网卡&#xff0c;进行路由通信…

【Linux系统】—— 冯诺依曼体系结构与操作系统初理解

【Linux系统】—— 冯诺依曼体系结构与操作系统初理解 1 冯诺依曼体系结构1.1 基本概念理解1.2 CPU只和内存打交道1.3 为什么冯诺依曼是这种结构1.4 理解数据流动 2 操作系统2.1 什么是操作系统2.2 设计OS的目的2.3 操作系统小知识点2.4 如何理解"管理"2.5 系统调用和…