# 实现签名认证
使用签名认证时,参数如下表所示:
参数名称 | 类型 | 必选 | 描述 |
---|---|---|---|
X-Jcc-Timestamp | Integer | 是 | 当前UNIX时间戳,可记录发起API请求的时间。 例如 1529223702。 注意:如果与服务器时间相差超过20秒,会引起签名过期错误。 |
X-Jcc-Service | String | 是 | 服务名称,当前固定取值:jcc-api |
X-Jcc-Authorization | String | 是 | HTTP 身份认证头部字段,凭证信息生成方式在实现方法中说明。 |
# 实现方法
获取客户鉴权密钥,具体请参见通过控制台使用短信服务中的获取鉴权密钥步骤。
拼接待签名字符串
按如下格式拼接待签名字符串:
StringToSign = Date + '/' + `jcc-api`
字段名称 | 描述 |
---|---|
Date | 请求当前日期,日期需要满足格式yyyy-mm-dd。 |
计算签名
计算签名的伪代码如下:
Signature = Base64(HMAC_SHA256(APISecret, StringToSign))
- 拼接 Authorization
按如下格式拼接 Authorization:
Authorization =
Algorithm + ' ' +
'key-id=' + SecretId + ',' +
'signed-headers=' + SignedHeaders + ', ' +
'Signature=' + Signature
字段名称 | 描述 |
---|---|
Algorithm | 签名方法,固定为:J-HMAC-SHA256。 |
SecretId | 密钥对中API Key。 |
SignedHeaders | 参与签名的头部信息。此示例取值为 x-jcc-timestamp;x-jcc-service。 |
Signature | 签名值。 |
最终完整的请求头如下:
X-Jcc-Timestamp: 1641370291
X-Jcc-Service: jcc-api
X-Jcc-Authorization: J-HMAC-SHA256 key-id="key-123",signed-headers="x-jcc-timestamp;x-jcc-service",signature="TrGC3BXmqVKEW89d35favUtYl6hIpcce%2BBQiodUqyRI%3D"
# 示例代码
- JAVA
示例代码采用Spring Boot框架自带的RestTemplate,如果采用其他HTTP框架请自行支持POST重定向。
- 支持POST的重定向
package com.juphoon.rcs.controller;
import org.apache.http.client.HttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.LaxRedirectStrategy;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.web.client.RestTemplate;
import java.util.Collections;
@Configuration
public class RestTemplateConfig {
@Bean("laxRestTemplate")
public RestTemplate laxRestTemplate() {
HttpComponentsClientHttpRequestFactory httpRequestFactory = new HttpComponentsClientHttpRequestFactory();
httpRequestFactory.setConnectionRequestTimeout(2000);
httpRequestFactory.setConnectTimeout(10000);
httpRequestFactory.setReadTimeout(72000);
HttpClient httpClient = HttpClientBuilder.create().setRedirectStrategy(new LaxRedirectStrategy()).build();
httpRequestFactory.setHttpClient(httpClient);
RestTemplate restTemplate = new RestTemplate(httpRequestFactory);
return restTemplate;
}
}
- 关键代码逻辑
package com.juphoon.rcs.controller;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.http.*;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import sun.misc.BASE64Encoder;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.util.Base64;
import java.util.Date;
@Slf4j
@RequestMapping("/test")
@RestController
public class TestController {
private static EchoEncoder encoder = new EchoEncoder();
@Autowired
private RestTemplate laxRestTemplate;
@GetMapping("/hmac")
public void hmacAuth() {
// 客户 API Key
final String customerAPIKey = "Your customer api key";
// 客户 API Secret
final String customerAPISecret = "Your customer api secret";
HttpHeaders httpHeaders = new HttpHeaders();
httpHeaders.setContentType(MediaType.APPLICATION_JSON);
String signedHeaders = "x-jcc-timestamp;x-jcc-service";
long time = System.currentTimeMillis();
String service = "jcc-api";
String date = date(time);
String signatureString = date + "/" + service;
String sign = null;
try {
sign = HMACSHA256(signatureString, customerAPISecret);
} catch (Exception e) {
e.printStackTrace();
}
String auth = "J-HMAC-SHA256 key-id=\"" + customerAPIKey + "\"," +
"signed-headers=\"" + signedHeaders + "\",signature=\"" + sign + "\"";
httpHeaders.add("X-Jcc-Timestamp", time / 1000 + "");
httpHeaders.add("X-Jcc-Service", "jcc-api");
httpHeaders.add("X-Jcc-Authorization", auth);
String body = "Your Send Payload Json String";
String urlString = "https://sms.api.juphoon.com/sms/v1";
HttpEntity requestEntity = new HttpEntity<>(body, httpHeaders);
ResponseEntity<String> response = laxRestTemplate.exchange(urlString, HttpMethod.POST, requestEntity, String.class);
}
public static String HMACSHA256(String data, String key) throws Exception {
Mac sha256_HMAC = Mac.getInstance("HmacSHA256");
SecretKeySpec secret_key = new SecretKeySpec(key.getBytes("UTF-8"), "HmacSHA256");
sha256_HMAC.init(secret_key);
byte[] array = sha256_HMAC.doFinal(data.getBytes("UTF-8"));
String encode = encoder.encode(array);
return URLEncoder.encode(encode, "UTF-8");
}
public static String date(Long time) {
Date date = new Date(time);
SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
return sdf.format(date);
}
}
- Golang
package main
import (
"crypto/hmac"
"crypto/sha256"
"encoding/base64"
"fmt"
"io/ioutil"
"net/http"
"net/url"
"strconv"
"strings"
"time"
)
const (
// 客户 API Key
customerAPIKey = "Your customer key"
// 客户 API Secret
customerAPISecret = "Your customer secret"
)
// HMac 认证实现
func main() {
client := &http.Client{}
req, err := http.NewRequest(
"POST",
"https://sms.api.juphoon.com/sms/v1",
strings.NewReader("Your send payload string"))
if err != nil {
fmt.Println(err)
return
}
// 增加 Authorization header
req.Header.Add("Content-Type", "application/json")
jHmacSha256(req)
// 发送 HTTP 请求
res, err := client.Do(req)
if err != nil {
fmt.Println(err)
return
}
defer res.Body.Close()
body, err := ioutil.ReadAll(res.Body)
if err != nil {
fmt.Println(err)
return
}
fmt.Println(string(body))
}
func jHmacSha256(req *http.Request) {
// 服务和签名头
service := "jcc-api"
signedHeaders := "x-jcc-timestamp;x-jcc-service"
// 生成时间戳
timestamp := time.Now().Unix()
date := time.Unix(timestamp, 0).UTC().Format("2006-01-02")
// 组装签名头
signatureString := fmt.Sprintf("%s/%s", date, service)
// Sha1签名头
key := []byte(customerAPISecret)
h := hmac.New(sha256.New, key)
h.Write([]byte(signatureString))
// Base64和URL Encode
sigString := base64.StdEncoding.EncodeToString(h.Sum(nil))
encodedString := url.QueryEscape(sigString)
// 组装授权信息
authToken := fmt.Sprintf(`J-HMAC-SHA256 key-id=%q,signed-headers=%q,signature=%q`,
customerAPIKey, signedHeaders, encodedString)
tt := strconv.Itoa(int(timestamp))
req.Header.Set("x-jcc-timestamp", tt)
req.Header.Set("x-jcc-service", service)
req.Header.Set("x-jcc-authorization", authToken)
}