package main
import (
"crypto/hmac"
"crypto/sha256"
"fmt"
"strconv"
"strings"
"time"
)
func sha256HMAC(key []byte, data []byte) []byte {
mac := hmac.New(sha256.New, key)
mac.Write(data)
return []byte(fmt.Sprintf("%x", mac.Sum(nil)))
}
func Sign(signKeyInfo string, sk string, body []byte) string {
// expiration := 1800
// signKeyInfo := fmt.Sprintf("%s/%s/%d/%d", ver, ak, time.Now().Unix(), expiration)
signKey := sha256HMAC([]byte(sk), []byte(signKeyInfo))
signResult := sha256HMAC(signKey, body)
return string(signResult)
}
func main() {
//控制台回调配置的ak、sk
var ak = "ak"
var sk = "sk"
//从header参数中获取
var signKeyInfo string
var signature string
//获取接受到http请求的body
var bodyPayload []byte
signInfos := strings.Split(signKeyInfo, "/")
if len(signInfos) != 4 {
panic("signKeyInfo error")
}
//请求过期
timestamp, _ := strconv.ParseInt(signInfos[2], 10, 64)
expiration, _ := strconv.ParseInt(signInfos[3], 10, 64)
if time.Now().Unix() > timestamp+expiration {
panic("timestamp or expiration error")
}
signatureCal := Sign(signKeyInfo, sk, bodyPayload)
//签名不通过
if signature != signatureCal {
panic("signature error")
}
fmt.Printf("ak: %s SignKeyInfo:%s\n", ak, signKeyInfo)
fmt.Printf("Signature:%s\n", signature)
}
import jakarta.servlet.ServletInputStream;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
@RestController
@RequestMapping
public class TestController {
@PostMapping("/callback")
public void readBody(HttpServletRequest request) throws Exception {
int len = request.getContentLength();
ServletInputStream iii = request.getInputStream();
byte[] buffer = new byte[len];
iii.read(buffer, 0, len);
String requestBody = new String(buffer, StandardCharsets.UTF_8);
String signKeyInfo = request.getHeader("SignKeyInfo"), signature = request.getHeader("Signature");
validateCallback(buffer,signKeyInfo, signature);
}
public void validateCallback(byte[] body, String signKeyInfo, String signature) throws Exception {
// 控制台回调配置的ak、sk
String ak = "", sk = "";
// 从header参数中获取
//String signKeyInfo = "", signature = ""; //SignKeyInfo、Signature
String[] signInfos = signKeyInfo.split("/");
if (signInfos.length != 4) {
System.out.println("签名信息不正确");
return;
}
long timestamp = Long.parseLong(signInfos[2]);
long expiration = Long.parseLong(signInfos[3]);
// if (System.currentTimeMillis() / 1000 > timestamp + expiration) {
// System.out.println("请求过期");
// return;
// }
String signatureCal = Sign(signKeyInfo, sk, body);
// 签名不通过
if (!signature.equals(signatureCal)) {
System.out.println("签名不通过");
return;
}
System.out.printf("ak: %s SignKeyInfo:%s\n", ak, signKeyInfo);
System.out.printf("签名通过 Signature:%s\n", signature);
}
public static String Sha256HMAC(String key, byte[] data) throws Exception {
Mac sha256_HMAC = Mac.getInstance("HmacSHA256");
SecretKeySpec keySpec = new SecretKeySpec(key.getBytes(), "HmacSHA256");
sha256_HMAC.init(keySpec);
byte[] hash = sha256_HMAC.doFinal(data);
byte[] hexChars = new byte[hash.length * 2];
for (int j = 0; j < hash.length; j++) {
byte[] s = String.format("%02x", hash[j] & 0xFF).getBytes();
hexChars[j * 2] = s[0];
hexChars[j * 2 + 1] = s[1];
}
return new String(hexChars);
}
public static String Sign(String signKeyInfo, String sk, byte[] data) throws Exception {
int expiration = 1800; // 有效时间, 单位是秒,根据业务的实际情况调整
long timestamp = System.currentTimeMillis() / 1000L;
String signKey = Sha256HMAC(sk, signKeyInfo.getBytes());
String signResult = Sha256HMAC(signKey, data);
return signResult;
}
}
<?php
namespace appcontroller;
use appBaseController;
use thinkacadeLog;
class Index extends BaseController
{
public function index()
{
return '<style>*{ padding: 0; margin: 0; }</style><iframe src="https://www.thinkphp.cn/welcome?version=' . hinkacadeApp::version() . '" width="100%" height="100%" frameborder="0" scrolling="auto"></iframe>';
}
public function hello($name = 'ThinkPHP8')
{
$signKeyInfo = $this->request->header("SignKeyInfo");
echo "SignKeyInfo: " . $signKeyInfo . "\n";
$signature = $this->request->header("Signature");
echo "Signature: " . $signature . "\n";
$body = $this->request->getContent();
echo "Body: " . $body . "\n";
$this->validateCallback($body, $signKeyInfo, $signature);
return "callbnack";
}
private function validateCallback($body, $signKeyInfo, $signature) {
// 控制台回调配置的ak、sk
$ak ="";
$sk ="";
$signInfos = explode("/", $signKeyInfo);
if (count($signInfos) != 4) {
echo "签名信息不正确";
return;
}
$timestamp = $signInfos[2];
$expiration = $signInfos[3];
if (time() > ($timestamp + $expiration)) {
echo "请求过期";
Log::channel("volc_back")->info("【火山回调】请求过期");
return;
}
$signatureCal = $this->sign($signKeyInfo, $sk, $body);
echo "签名计算结果: " . $signatureCal . "\n";
// 签名不通过
if ($signature != $signatureCal) {
echo "签名不通过";
return;
}
echo "ak: " . $ak . " SignKeyInfo:" . $signKeyInfo . "\n";
echo "签名通过 Signature:" . $signature . "\n";
}
private function sha256HMAC($key, $data)
{
$hash = hash_hmac('sha256', $data, $key, true);
$hexChars = '';
for ($j = 0; $j < strlen($hash); $j++) {
$hexChars .= sprintf("%02x", ord($hash[$j]));
}
return $hexChars;
}
private function sign($signKeyInfo, $sk, $data)
{
$expiration = 1800;
$timestamp = time();
$signKey = $this->sha256HMAC($sk, $signKeyInfo);
return $this->sha256HMAC($signKey, $data);
}
}