开放平台设计之接口签名认证

目录

前言

签名认证

签名认证步骤:

下面以java代码举例:

DEMO


前言

当前时代,数据是王 道!当我们自己的平台有了足够大的数据量,就有可能诞生一个开放平台供第三方分析、使用。那么我们怎么去实现对外部调用接口的控制与鉴权呢?这是我们今天的重点——接口签名认证!!!

签名认证

开放平台会为每一位注册用户分配一个对应账户API KEY和秘钥API SECRET。我们为了保证接口的安全性,用户在每次接口的调用都需要上传一个所谓的签名(基于API KEYAPI SECRET获取)

签名认证步骤:

  1. 首先生成一个Unix时间戳timestamp,时间精确到毫秒【即1970年1月1日(UTC/GMT的午夜)开始所经过的毫秒数】;
  2. 生成随机数nonce(注:目前定义的是32位的,可以通过随机数工具类生成) ;
  3. 1)将timestamp、nonce、API_KEY 这三个字符串依据“字符串首位字符的ASCII码”进行升序排列(排序过程中若出现ASCII码值相同的情况,则依次递增对下一位进行比较)(这种排序,”也就是俗称的字典序“),并将排序后的结果拼接成为一个字符串join_str;
    2)接下来在用API_SECRET对上面生成这个字符串join_str做hmac-sha256 签名,并且以16进制编码,得到signature
  4. 将上述得到的timestampnonce,signature,与 API_KEY按照 #{k}=#{v}并以 ',' 为区分拼接在一起形成新的字符串,这就是要返回签名认证字符串authorization;
  5. 当完成以上4步,我们就可以获取最终的签名认证字符串了。调用接口时,将通过签名认证步骤得到的值authorization 传给HTTP HEADER的Authorization对应的值;请求体部分按照相对应文档请求参数说明正确填写,正常发送请求,即可完成一次接口调用。

下面以java代码举例:

假设 API_KEY = "233453f1d1eb4eb5a5ad9c8dac0d02cc";
API_SECRETS = "444af44cd3a247c594438fb60d7b1d52";

1. 获得timestamp(unix时间戳),返回timestamp :"1633431976787"

实现方式:

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

2. 获得随机nonce,返回nonce: "3isQFsTjsnNOLvIPXhf3HlW17WSfQqp9"

可用下面方式实现:

String nonce = RandomStringUtils.randomAlphanumeric(32);

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

可用下面方式实现:

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;
    }

4. 用API_SECRET对join_str做hmac-sha256签名,且以16进制编码,返回signature:"7d37d14406323f0ab30d1d4db1e7f2eb27abac42f3de00d619025108fa6cd5e4"

可用下面方式实现:

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;
    }

5. 将上述的值按照 #{k}=#{v} 并以 ',' join在一起,返回签名认证字符串:
"key=2371d3f1d1eb4eb5a5ad9c8dac0d02cc,timestamp=1638431976741,nonce=3isWSsTjsnNOLvIPXhf3HlW17WSfQqp9,signature=7d37d14406323f0ab30d1d4db1e7f2eb27abac42f3de00d619025108fa6cd5e4"

可用下面方式实现:

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;
    }

6. 将该签名认证字符串赋值给HTTP HEADER 的 Authorization 中,完成一次接口访问。

DEMO

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>

具体实现代码:


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;
     }
}
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);
    }
}

好了,今天关于开放平台之接口认证鉴权就到这里。

欢迎大家点击下方卡片关注《coder练习生》

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

ybb_ymm

你的鼓励会是对我最大的支持

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值