OpenAPI的签名校验

news2024/9/21 4:36:17

前言

作为一个后端开发,提供API接口或者对接第三方API接口的时候,考虑接口的防刷、重放等安全问题,严格意义上,都需要加上双方约定的签名规则。

大致思路

一般情况下,签名规则没有墨守成规的规定,只要考虑过期性、安全性即可,不用把他想的很高大上。

事先准备

准备API KEY和秘钥API SECRET,这个通常由API提供方自己生产,不固定,只要保证不泄露即可。

一、时间戳(timestamp)

生成一个Unix时间戳timestamp,时间精确到毫秒【即1970年1月1日(UTC/GMT的午夜)开始所经过的毫秒数】;实现方式如下:

 String timestamp = Long.toString(System.currentTimeMillis()); 

二、生成随机字符(nonce)

生成随机数nonce(注:目前定义的是32位的,可以通过随机数工具类生成) ;实现方式比如:

String nonce = RandomStringUtils.randomAlphanumeric(32);

三、生成签名signature

1)将timestamp、nonce、API_KEY 这三个字符串依据“字符串首位字符的ASCII码”进行升序排列(排序过程中若出现ASCII码值相同的情况,则依次递增对下一位进行比较)(这种排序,”也就是俗称的字典序“),并将排序后的结果拼接成为一个字符串join_str;
2)接下来在用API_SECRET对上面生成这个字符串join_str做hmac-sha256 签名,(其他加密方式也可以,没有固定)并且以16进制编码,得到signature;

四、参数拼接

将上述得到的timestamp,nonce,signature,与 API_KEY按照 #{k}=#{v}并以 ‘,’ 为区分拼接在一起形成新的字符串,这就是要返回签名认证字符串authorization;也可以不拼接,直接将timestamp、nonce、signature三个参数放入HTTP请求头即可,形式不唯一。

关键代码演示

将timestamp、nonce、API_KEY 这三个字符串依据“字符串首位字符的ASCII码”进行升序排列(排序过程中若出现ASCII码值相同的情况,则依次递增对下一位进行比较),并join成一个字符串

public static String genOriString(String timestamp,String nonce,String API_KEY){
 
        ArrayList<String> beforesort = new ArrayList<String>();
        beforesort.add(API_KEY);
        beforesort.add(timestamp);
        beforesort.add(nonce);
 
        Collections.sort(beforesort, new SpellComparator());
        StringBuffer aftersort = new StringBuffer();
        for (int i = 0; i < beforesort.size(); i++) {
            aftersort.append(beforesort.get(i));
        }
 
        String join_str = aftersort.toString();
        return join_str;
    }

用API_SECRET对join_str做hmac-sha256签名,且以16进制编码,返回

public static String genEncryptString(String join_str, String API_SECRET){
 
        Key sk = new SecretKeySpec(API_SECRET.getBytes(), "HmacSHA256");
        Mac mac = Mac.getInstance(sk.getAlgorithm());
        mac.init(sk);
        final byte[] hmac = mac.doFinal(join_str.getBytes());//完成hmac-sha256签名
        StringBuilder sb = new StringBuilder(hmac.length * 2);
        Formatter formatter = new Formatter(sb);
            for (byte b : hmac) {
                formatter.format("%02x", b);
            }
        String signature = sb.toString();//完成16进制编码
        return signature;
    }

将上述的值按照 #{k}=#{v} 并以 ‘,’ join在一起,返回签名认证字符串:

public static String genauthorization(String API_KEY, String timestamp, String nonce, String signature){
 
        String authorization = "key=" + API_KEY
                     +",timestamp=" + timestamp
                         +",nonce=" + nonce
                     +",signature=" + signature;
        return authorization;
    }

SpringBoot的pom依赖

     <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <version>3.12.0</version>
     </dependency>
 
     <dependency>
            <groupId>org.apache.httpcomponents</groupId>
            <artifactId>httpmime</artifactId>
            <version>RELEASE</version>
            <scope>compile</scope>
     </dependency>

SpellComparator 类

 
import java.util.Comparator;
 
 
public class SpellComparator implements Comparator<Object> {
    public int compare(Object o1, Object o2) {
        try{
            String s1 = new String(o1.toString().getBytes("GB2312"), "ISO-8859-1");
            String s2 = new String(o2.toString().getBytes("GB2312"), "ISO-8859-1");
            return s1.compareTo(s2);
        }catch (Exception e){
            e.printStackTrace();
        }
        return 0;
     }
}

完整生成的Demo

import java.io.IOException;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.NoSuchAlgorithmException;
import java.security.SignatureException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Formatter;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.http.client.ClientProtocolException;
 
 
public class GenerateString {
    // 开放平台注册获取id(API KEY)
    public static final String id = "22bfe9745135";
    // 开放平台注册获取密钥(API SECRET)
    public static final String secret = "19fbdc10";
 
    private static final String HASH_ALGORITHM = "HmacSHA256";
    static String timestamp = Long.toString(System.currentTimeMillis());
    static String nonce = RandomStringUtils.randomAlphanumeric(32);
 
    public static String genOriString(String api_key){
 
        ArrayList<String> beforesort = new ArrayList<String>();
        beforesort.add(api_key);
        beforesort.add(timestamp);
        beforesort.add(nonce);
 
        Collections.sort(beforesort, new SpellComparator());
        StringBuffer aftersort = new StringBuffer();
        for (int i = 0; i < beforesort.size(); i++) {
            aftersort.append(beforesort.get(i));
        }
 
        String OriString = aftersort.toString();
        return OriString;
    }
 
    public static String genEncryptString(String genOriString, String api_secret)throws SignatureException {
        try{
            Key sk = new SecretKeySpec(api_secret.getBytes(), HASH_ALGORITHM);
            Mac mac = Mac.getInstance(sk.getAlgorithm());
            mac.init(sk);
            final byte[] hmac = mac.doFinal(genOriString.getBytes());
            StringBuilder sb = new StringBuilder(hmac.length * 2);
 
            @SuppressWarnings("resource")
            Formatter formatter = new Formatter(sb);
            for (byte b : hmac) {
                formatter.format("%02x", b);
            }
            String EncryptedString = sb.toString();
            return EncryptedString;
        }catch (NoSuchAlgorithmException e1){
            throw new SignatureException("error building signature, no such algorithm in device "+ HASH_ALGORITHM);
        }catch (InvalidKeyException e){
            throw new SignatureException("error building signature, invalid key " + HASH_ALGORITHM);
        }
    }
 
    public static String genHeaderParam(String api_key, String api_secret) throws SignatureException{
 
        String GenOriString = genOriString(api_key);
        String EncryptedString = genEncryptString(GenOriString, api_secret);
 
        String HeaderParam = "key=" + api_key
                +",timestamp=" + timestamp
                +",nonce=" + nonce
                +",signature=" + EncryptedString;
        System.out.println(HeaderParam);
        return HeaderParam;
    }
 
    public static void main(String[] args) throws ClientProtocolException, IOException, SignatureException{
        String s = genHeaderParam(id, secret);
        System.out.println(s);
    }
}

写在最后

这个是参考一位兄弟的博文整理的,确实挺不错,简单实用,至于接口签名校验,就把调用方的几个参数进行校验生成签名sign,比对两个签名sign和对方常来的signature是否一致即可,最好对传来的时间戳进行校验,可以设置10分钟有效。
好了,今天的分享就到这,兄弟姐妹们,520快乐,欢迎持续关注"安前码后",一个注重工作干货的号。

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

MediaPipe Face Detection可运行在移动设备上的亚毫秒级人脸检测

MediaPipe人脸检测 MediaPipe人脸检测是一种超快速的人脸检测解决方案,具有6个界标和多人脸支持。它基于BlazeFace,BlazeFace是为移动GPU推理量身定制的轻巧且性能良好的面部检测器。检测器的超实时性能使其可应用于需要准确地关注面部区域作为其他任务特定模型: 例如 1、3…

如何有效解决企业文件安全事件频发问题?

企业文件安全是企业必须解决的一个关键问题。随着数字化趋势的不断发展&#xff0c;企业严重依赖于以电子格式存储和访问数据。这种转变使得组织必须实施适当的安全协议&#xff0c;以确保其敏感数据免受未经授权的访问或盗窃。 企业网盘的使用已经在公司中流行起来&#xff0c…

ChatGPT:3. 使用OpenAI创建自己的AI网站:2. 使用 flask web框架快速搭建网站主体

使用OpenAI创建自己的AI网站 如果你还是一个OpenAI的小白&#xff0c;有OpenAI的账号&#xff0c;但想调用OpenAI的API搞一些有意思的事&#xff0c;那么这一系列的教程将仔细的为你讲解如何使用OpenAI的API制作属于自己的AI网站。博主只能利用下班时间更新&#xff0c;进度慢…

mybatis是如何集成到spring的之SqlSessionFactoryBean

文章目录 1 前言1.1 集成spring前使用mybatis的方式1.2 集成mybatis到spring的关键步骤 2 SqlSessionFactoryBean对象分析2.1 buildSqlSessionFactory做了什么事情&#xff1f;2.2 为什么是SqlSessionFactoryBean却可以使用SqlSessionFactory&#xff1f; 3 验证demo4 举一反三…

【QT】自定义工程封装成DLL并如何调用(带ui界面的)

一、动态库的封装 1、首先新建一个Library工程 2、修改类型为共享库&#xff0c;自定义项目名称以及项目路径 3、选择编译器 4、选择动态库所需要的模块 5、自定义类名&#xff0c;点击下一步 6、点击下一步 7、项目总览 8、此时的文件中还没有ui文件&#xff0c;因为要封装带…

南京邮电大学算法与设计实验四:回溯法(最全最新,与题目要求一致)

要求用回溯法求解8-皇后问题&#xff0c;使放置在8*8棋盘上的8个皇后彼此不受攻击&#xff0c;即&#xff1a;任何两个皇后都不在同一行、同一列或同一斜线上。请输出8皇后问题的所有可行解。 用回溯法编写一个递归程序解决如下装载问题&#xff1a;有n个集装箱要装上2艘载重分…

pg事务:隔离级别(2)

事务隔离级别的历史 ANSI SQL-92定义的隔离级别和异常现象确实对数据库行业影响深远&#xff0c;甚至30年后的今天&#xff0c;绝大部分工程师对事务隔离级别的概念还停留在此&#xff0c;甚至很多真实的数据库隔离级别实现也停留在此。但后ANSI92时代对事物隔离有许多讨论甚至…

【5.20】五、安全测试——渗透测试

目录 5.3 渗透测试 5.3.1 什么是渗透测试 5.3.2 渗透测试的流程 5.3 渗透测试 5.3.1 什么是渗透测试 渗透测试是利用模拟黑客攻击的方式&#xff0c;评估计算机网络系统安全性能的一种方法。这个过程是站在攻击者角度对系统的任何弱点、技术缺陷或漏洞进行主动分析&#x…

如何在项目管理中实现任务活动的留痕管理?

项目工作为什么需要留痕呢? 1&#xff0c;记录项目工作&#xff1a;在项目管理工作中常常涉及多部门协作&#xff0c;工作留痕可以帮助我们有效复原已经发生了的工作活动&#xff0c;从而留下印迹供日后查证。 2&#xff0c;支撑工作复盘&#xff1a;在项目工作结束之后&…

SpringBoot程序启动速度提速分析

传统的破程序&#xff08;百万行级一个微服务&#xff09;&#xff0c;在我的P15-gen2代电脑上启动一次需要80秒左右(直接运行三次&#xff0c;取平均值&#xff09;&#xff0c;在其它人电脑上可想而知了。 大概记录几点 1 优化肯定是需要找工具观察的&#xff0c;不观测还…

MyBatis、MyBatis-plus

文章目录 MyBatis一、MyBatis简介1. 什么是MyBatis2. MyBatis开发步骤3. 环境搭建4. MyBatis的映射文件&#xff08;UserMapper)5. 动态sql语句6. MyBatis的增删改查 二、MyBatis核心配置文件&#xff08;sqlMapConfig&#xff09;1. MyBatis常用配置1&#xff09;environments…

使用JAVA代码实现跳动爱心(脱单节程序员必备哦)

520&#xff01;&#xff01;&#xff01;表白日&#xff0c;你脱单了吗&#xff1f;你跟对象彻夜不归了吗&#xff1f; 如果没有说明&#xff0c;你的诚心不够&#xff0c;来给对象一个代码表白吧&#xff01; 话不多说&#xff0c;先上效果图&#xff1a; 实现代码如下&…

kicad学习笔记6:kicad启动及其grid参数设置和修改

1。kicad启动&#xff1a; single_top.cpp 启动函数&#xff1a; 1。 IMPLEMENT_APP( APP_SINGLE_TOP )2。 PGM_SINGLE_TOP::OnPgmInit()3。 PGM_BASE::InitPgm2。kicad参数 grid参数定义&#xff1a; struct GRID_SETTINGS {bool axes_enabled;std::vector<wxString&…

华为OD机试真题 Java 实现【天然蓄水池】【2023Q1 200分】

一、题目描述 公元2919年&#xff0c;人类终于发现了一颗宜居星球——X星。现想在X星一片连绵起伏的山脉间建一个天然蓄水库&#xff0c;如何选取水库边界&#xff0c;使蓄水量最大&#xff1f; 要求&#xff1a; 山脉用正整数数组s表示&#xff0c;每个元素代表山脉的高度。…

基于springboot人事管理系统

末尾获取源码 开发语言&#xff1a;Java Java开发工具&#xff1a;JDK1.8 后端框架&#xff1a;SpringBoot 前端&#xff1a;Vue 数据库&#xff1a;MySQL5.7和Navicat管理工具结合 开发软件&#xff1a;IDEA / Eclipse 是否Maven项目&#xff1a;是 前言 基于springboot人事管…

vscode录音及语音实时转写插件开发并在工作区生成本地mp3文件 踩坑日记!

前言 最近接到一个需求&#xff0c;实现录音功能并生成mp3文件到本地工作区&#xff0c;一开始考虑到的是在vscode主体代码里面开发&#xff0c;但这可不是一个小的工作量。时间紧&#xff0c;任务重&#xff01;市面上实现录音功能的案例其实很多&#xff0c;一些功能代码是可…

【敬伟ps教程】修复工具

文章目录 模糊工具锐化工具涂抹工具减淡、加深工具海绵工具仿制图章工具图案图章工具修复画笔工具污点修复画笔工具修补工具内容感知移动工具红眼工具 模糊工具 模糊工具的主要功能就是把图像变的模糊。虽然是把图像变模糊&#xff0c;但是模糊工具应用也是很广泛的。使用模糊工…

小黑子—Java从入门到入土过程:第十一章 - 网络编程、反射及动态代理

Java零基础入门11.0 网络编程1. 初识网络编程2. 网络编程三要素3.IP三要素3.1 IPV4的细节3.1.1特殊的IP地址3.1.2 常用的CMD命令 3.2 InetAddress 的使用3.3 端口号3.4 协议3.4.1 UDP协议3.4.1 - I UDP 发送数据3.4.1 - II UDP 接收数据3.4.1 - III UDP 练习&#xff08;聊天室…

C++实现日期类(超详细)

个人主页&#xff1a;平行线也会相交&#x1f4aa; 欢迎 点赞&#x1f44d; 收藏✨ 留言✉ 加关注&#x1f493;本文由 平行线也会相交 原创 收录于专栏【C之路】&#x1f48c; 本专栏旨在记录C的学习路线&#xff0c;望对大家有所帮助&#x1f647;‍ 希望我们一起努力、成长&…

六级备考28天|CET-6|听力第二讲|长对话满分技巧|听写技巧|2022年6月考题|14:30~16:00

目录 1. 听力策略 2. 第一二讲笔记 3. 听力原文复现 (5)第五小题 (6)第六小题 (7)第七小题 (8)第八小题 扩展业务 expand business 4. 重点词汇 1. 听力策略 2. 第一二讲笔记 3. 听力原文复现 (5)第五小题 our guest is Molly Sundas, a university stud…