签名认证
我们会为每位公有云用户分配一个API KEY和一个API SECRET。为了保证安全性,用户的每次访问都需要上传一个签名(基于API KEY和API SECRET获取)。
具体签名方法:
- 用户自己生成 timestamp(Unix 时间戳), 以及一个随机 nonce,外加自己的 API_KEY。
- 将timestamp、nonce、API_KEY 这三个字符串进行升序排列(依据字符串首位字符的ASCII码),并join成一个字符串,然后用API_SECRET对这个字符串做hamc-sha256 签名,以16进制编码。
- 将上述得到的签名结果作为 signature 的值,与 API_KEY, nonce, timestamp 一起放在HTTP HEADER 的 Authorization 中。
下面以java代码举例:
- 假设API_KEY = "abcedfg"; API_SECRET = "1234567890"
- 获得timestamp(unix时间戳),实现方式:
- String timestamp = System.currentTimeMillis() + "";
返回timestamp :"1471924244823"
- 获得随机nonce,最好是32位的uuid,可用下面方式实现:
- public static synchronized String getUUID(){
- UUID uuid=UUID.randomUUID();
- String str = uuid.toString();
- String nonce=str.replace("-", "");
- return nonce;
- }
返回nonce: "86cb646a267c4602913f2034bce0cea4"
- 将timestamp、nonce、API_KEY 这三个字符串进行升序排列(依据字符串首位字符的ASCII码),并join成一个字符串,可用下面方式实现:
- public static String genjoinstr(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;
- }
返回join_str:147192424482386cb646a267c4602913f2034bce0cea4abcdefg
- 用API_SECRET对join_str做hamc-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());//完成hamc-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;
- }
返回经过16进制编码的hamc-sha256签名signature:
eea4300393cd859421fa8eb074781df93ca95d120e9ed0b7b4a92b4537fbccd1
- 将上述的值按照 #{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;
- }
返回签名认证字符串:key=abcdefg,timestamp=1471924244823,nonce=86cb646a267c4602913f2034bce0cea4,signature=eea4300393cd859421fa8eb074781df93ca95d120e9ed0b7b4a92b4537fbccd1
- 将该签名认证字符串赋值给HTTP HEADER 的 Authorization 中,完成一次接口访问。
C++ 样例
#include <stdio.h>
#include <string.h>
#include <iostream>
#include <algorithm>
#include <string>
#include <time.h>
#include <stdlib.h>
#include <sstream>
#include <objbase.h>
#include<fstream>
#include <openssl/hmac.h>
#define GUID_LEN 33
using namespace std;
int HmacEncode(const char * key, unsigned int key_length,const char * input, unsigned int input_length,
unsigned char * &output, unsigned int &output_length) {
const EVP_MD * engine = NULL;
engine = EVP_sha256();
output = (unsigned char*)malloc(EVP_MAX_MD_SIZE);
HMAC_CTX ctx;
HMAC_CTX_init(&ctx);
HMAC_Init_ex(&ctx, key, strlen(key), engine, NULL);
HMAC_Update(&ctx, (unsigned char*)input, strlen(input)); // input is OK; &input is WRONG !!!
HMAC_Final(&ctx, output, &output_length);
HMAC_CTX_cleanup(&ctx);
return 0;
};
int main()
{
//--------获取timestamp
time_t tick;
tick = time(NULL);
char ntimestamp[512] = { 0 };
_snprintf_s(ntimestamp, sizeof(ntimestamp), "%ld", (long)tick);
//--------获取nonce
char nonce[512] = {0};
GUID guid;
if (CoCreateGuid(&guid))
{
fprintf(stderr, "create guid error\n");
return -1;
}
_snprintf_s(nonce, sizeof(nonce),
"%08x%04x%04x%02x%02x%02x%02x%02x%02x%02x%02x",
guid.Data1, guid.Data2, guid.Data3,
guid.Data4[0], guid.Data4[1], guid.Data4[2],
guid.Data4[3], guid.Data4[4], guid.Data4[5],
guid.Data4[6], guid.Data4[7]);
//--------赋值API_KEY
char api_key[512] = "XXXXXX";
//--------
char pre_authority[100] = { 0 };
_snprintf_s(pre_authority, sizeof(pre_authority),
"key=%s,timestamp=%s,nonce=%s", api_key, ntimestamp, nonce);
//--------pre_authority
//--------对timestamp、nonce、API_KEY进行排序连接为str1
char *str1 = &ntimestamp[0];//timestamp
char *str2 = &nonce[0];//nonce
char *str3 = &api_key[0];//api_key
if (str1[0] > str2[0])
{
swap(str1, str2);
}
if (str2[0] > str3[0])
{
swap(str2, str3);
}
if (str1[0] > str2[0])
{
swap(str1, str2);
}
strcat_s(str1, 128, str2);
strcat_s(str1, 128, str3);
//---------赋值API_SECRET
char secret[] = "xxxxxx";//API_SECRET
//---------用API_SECRET对str1做hamc-sha256签名
unsigned int mac_int[32];
unsigned char mac_char64[100];
unsigned int mac_mid;
unsigned char * mac = NULL;
unsigned int mac_length = 0;
int j = 0;
int ret = HmacEncode(secret, strlen(secret), str1, strlen(str1), mac, mac_length);
//将签名结果转为16进制字符串,存到mac_char64数组作为signature
for (int i = 0; i < mac_length; i++) {
printf("%-03x", (unsigned int)mac[i]);
mac_int[i] = (unsigned int)mac[i];
}
printf("\n");
for (int i = 0; i < mac_length; i++) {
mac_mid = ((mac_int[i] & 0x00f0) >> 4);
if (mac_mid >= 10)
{
mac_char64[j++] = mac_mid + 87;
}
else
{
mac_char64[j++] = mac_mid + 48;
}
mac_mid = (mac_int[i] & 0x000f);
if (mac_mid >= 10)
{
mac_char64[j++] = mac_mid + 87;
}
else
{
mac_char64[j++] = mac_mid + 48;
}
}
mac_char64[64] = '\0';
//---------将key,timestamp,nonce,mac_char64组合成指定格式的字符串赋值给authority
char authority[256] = {0};
_snprintf_s(authority, sizeof(authority),
"%s,signature=%s", pre_authority, mac_char64);
free(mac);
system("pause");
return 0;
}
Java 样例
package auth_new;
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;
}
}
package auth_new;
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.lang.RandomStringUtils;
import org.apache.http.client.ClientProtocolException;
import resources.Constants;
public class GenerateString {
public static final String id = Constants.ID;
public static final String secret = Constants.SECRET;
private static final String HASH_ALGORITHM = "HmacSHA256";
static String api_key = "xxxx";
static String api_secret = "xxxx";
static String timestamp = Long.toString(System.currentTimeMillis());
static String nonce = RandomStringUtils.randomAlphanumeric(16);
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{
genHeaderParam(id, secret);
}
}
Ruby 样例
# -*- coding: UTF-8 -*-
require 'openssl'
require 'rubygems'
require 'uuidtools'
seq=["","",""]
timestamp=Time.now.to_i #获取timestamp
nonce=UUIDTools::UUID.timestamp_create().to_s
nonce.gsub!('-','') #获取nonce
API_KEY="xxxxxx"
API_SECRET="xxxxxx"
seq[0]=timestamp.to_s
seq[1]=nonce.to_s
seq[2]=API_KEY
0.upto(seq.length-1) do |i|
exchange = false
0.upto(seq.length-1-i-1) do|j|
if seq[j]>=seq[j+1]
tmp = seq[j+1]
seq[j+1] = seq[j]
seq[j] = tmp
exchange = true
end
end
if !exchange
break
end
end
seq.each {|num| puts num}
str=seq[0]+seq[1]+seq[2] #获取timestamp,nonce,API_KEY的排序串联字符串
puts str
signature = OpenSSL::HMAC.hexdigest('sha256', API_SECRET, str) #用API_SECRET对串联字符串做签名
authority='key='+API_KEY+',nonce='+nonce.to_s+',timestamp='+timestamp.to_s+',signature='+signature #组成authority
PHP 样例
<?php
define("API_KEY", "Your API_KEY");
define("API_SECRET", "Your API_SECRET");
function signString($string_to_sign, $API_SECRET) {
//对两个字符串做hamc-sha256 签名
return hash_hmac("sha256", $string_to_sign, $API_SECRET);
}
function makeNonce( $length) {
// 生成随机 nonce。位数可以自己定
$chars = 'abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789';
$nonce = '';
for ( $i = 0; $i < $length; $i++ ) {
$nonce .= $chars[ mt_rand(0, strlen($chars) - 1) ];
}
return $nonce;
}
function makeStringSignature($nonce,$timestamp,$API_KEY){
//将timestamp、nonce、API_KEY 这三个字符串进行升序排列(依据字符串首位字符的ASCII码),并join成一个字符串
$payload = array(
'API_KEY' => API_KEY,
'nonce' => $nonce,
'timestamp' => $timestamp
);
//对首字母排序
sort($payload);
//join到一个字符串
$signature = join($payload);
return $signature;
}
//生成nonce
$nonce = makeNonce(16);
//生成unix 时间戳timestamp
$timestamp = (string) time();
//将timestamp、nonce、API_KEY 这三个字符串进行升序排列(依据字符串首位字符的ASCII码),并join成一个字符串stringSignature
$stringSignature = makeStringSignature($nonce,$timestamp,API_KEY);
//对stringSignature和API_SECRET做hamc-sha256 签名,生成signature
$signature = signString($stringSignature, API_SECRET);
//将签名认证字符串赋值给HTTP HEADER 的 Authorization 中
$Authorization = "key=".API_KEY.",timestamp=".$timestamp.",nonce=".$nonce.",signature=".$signature;
echo "Authorization:";
echo "<br>";
echo($Authorization);
$testurl = 'https://v2-auth-api.visioncloudapi.com/info/api';
$ch = curl_init();
$header= array(
'Content-Type: application/json',
'Authorization: '.$Authorization
);
curl_setopt($ch, CURLOPT_HTTPHEADER, $header);
curl_setopt($ch, CURLOPT_URL, $testurl);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE);
//打开SSL验证时,需要安装openssl库。也可以选择关闭,关闭会有风险。
$output = curl_exec($ch);
var_dump($output);
$output_array = json_decode($output,true);
curl_close($ch);
?>
C# 样例
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
namespace XXXX
{
/// <summary>
/// 授权认证帮助类
/// </summary>
public class AuthHelper
{
/// <summary>
/// 获取签名认证字符串
/// </summary>
/// <param name="name">登录名</param>
/// <param name="pwd">密码</param>
/// <param name="platid">授权平台ID</param>
/// <returns></returns>
public static string GetAuthString(string name, string pwd, string platid = null)
{
string
API_KEY = name,
API_SECRET = pwd,
timestamp = GetTimestamp(DateTime.Now).ToString(),
nonce = GetNonce();
string
join_str = GenJoinStr(timestamp, nonce, API_KEY, platid),
signature = GenEncryptString(join_str, API_SECRET);
return GenAuthorization(API_KEY, timestamp, nonce, signature, platid);
}
/// <summary>
/// 获取时间戳
/// </summary>
/// <param name="time">本地时间</param>
/// <returns>时间戳</returns>
public static long GetTimestamp(DateTime time)
{
return (time.ToUniversalTime().Ticks - 621355968000000000) / 10000000;
}
/// <summary>
/// 获取随机nonce
/// </summary>
/// <returns></returns>
public static string GetNonce()
{
return Guid.NewGuid().ToString().Replace("-", string.Empty);
}
/// <summary>
/// 将timestamp、nonce、API_KEY 这三个字符串进行升序排列(依据字符串首位字符的ASCII码),并join成一个字符串
/// </summary>
/// <param name="timestamp"></param>
/// <param name="nonce"></param>
/// <param name="API_KEY"></param>
/// <param name="platid">授权平台ID</param>
/// <returns></returns>
public static string GenJoinStr(string timestamp, string nonce, string API_KEY, string platid = null)
{
List<string> beforesort = new List<string>();
beforesort.Add(API_KEY);
beforesort.Add(timestamp);
beforesort.Add(nonce);
if (!string.IsNullOrWhiteSpace(platid))
beforesort.Add(platid);
beforesort.Sort();
StringBuilder aftersort = new StringBuilder();
for (int i = 0; i < beforesort.Count; i++)
aftersort.Append(beforesort[i]);
string join_str = aftersort.ToString();
return join_str;
}
/// <summary>
/// 用API_SECRET对join_str做hamc-sha256签名,且以16进制编码
/// </summary>
/// <param name="join_str"></param>
/// <param name="API_SECRET"></param>
/// <returns></returns>
public static string GenEncryptString(string join_str, string API_SECRET)
{
StringBuilder sb = new StringBuilder();
var encoding = new ASCIIEncoding();
byte[] keyByte = encoding.GetBytes(API_SECRET);
byte[] messageBytes = encoding.GetBytes(join_str);
using (var hmacsha256 = new HMACSHA256(keyByte))
{
byte[] hashmessage = hmacsha256.ComputeHash(messageBytes);
foreach (byte b in hashmessage)
sb.Append(b.ToString("x2"));
return sb.ToString();
}
}
/// <summary>
/// 将上述的值按照 #{k}=#{v} 并以 ',' join在一起
/// </summary>
/// <param name="API_KEY"></param>
/// <param name="timestamp"></param>
/// <param name="nonce"></param>
/// <param name="signature"></param>
/// <param name="platid">授权平台ID</param>
/// <returns></returns>
public static string GenAuthorization(string API_KEY, string timestamp, string nonce, string signature, string platid = null)
{
string authorization =
"key=" + API_KEY
+ ",timestamp=" + timestamp
+ ",nonce=" + nonce
+ ",signature=" + signature;
if (!string.IsNullOrWhiteSpace(platid))
authorization += ",platid=" + platid;
return authorization;
}
}
}