You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

388 lines
12 KiB
PHTML

5 years ago
<?php
require_once("YopRequest.php");
require_once("YopResponse.php");
require_once("YopError.php");
require_once("Util/HttpRequest.php");
require_once("Util/StringUtils.php");
require_once("Util/HttpUtils.php");
require_once("Util/Base64Url.php");
class YopRsaClient
{
public function __construct()
{
}
/**
* @param $methodOrUri
* @param $YopRequest
* @param $encode_data
* @return array
*/
public static function SignRsaParameter($methodOrUri, $YopRequest)
{
$appKey = $YopRequest->{$YopRequest->config->APP_KEY};
if (empty($appKey)) {
$appKey = $YopRequest->config->CUSTOMER_NO;
$YopRequest->removeParam($YopRequest->config->APP_KEY);
}
if (empty($appKey)) {
error_log("appKey 与 customerNo 不能同时为空");
}
date_default_timezone_set('PRC');
$dataTime = new DateTime();
$timestamp = $dataTime->format(DateTime::ISO8601); // Works the same since const ISO8601 = "Y-m-d\TH:i:sO"
$headers = array();
$headers['x-yop-appkey'] = $YopRequest->appKey;
$headers['x-yop-request-id'] = $YopRequest->requestId;
$protocolVersion = "yop-auth-v2";
$EXPIRED_SECONDS = "1800";
$authString = $protocolVersion . "/" . $appKey . "/" . $timestamp . "/" . $EXPIRED_SECONDS;
$headersToSignSet = array();
array_push($headersToSignSet, "x-yop-request-id");
$appKey = $YopRequest->{$YopRequest->config->APP_KEY};
if (!StringUtils::isBlank($YopRequest->config->CUSTOMER_NO)) {
$headers['x-yop-customerid'] = $appKey;
array_push($headersToSignSet, "x-yop-customerid");
}
// Formatting the URL with signing protocol.
$canonicalURI = HttpUtils::getCanonicalURIPath($methodOrUri);
// Formatting the query string with signing protocol.
$canonicalQueryString = YopRsaClient::getCanonicalQueryString($YopRequest, true);
// Sorted the headers should be signed from the request.
$headersToSign = YopRsaClient::getHeadersToSign($headers, $headersToSignSet);
// Formatting the headers from the request based on signing protocol.
$canonicalHeader = YopRsaClient::getCanonicalHeaders($headersToSign);
$signedHeaders = "";
if ($headersToSignSet != null) {
foreach ($headersToSign as $key => $value) {
$signedHeaders .= strlen($signedHeaders) == 0 ? "" : ";";
$signedHeaders .= $key;
}
$signedHeaders = strtolower($signedHeaders);
}
$canonicalRequest = $authString . "\n" . $YopRequest->httpMethod . "\n" . $canonicalURI . "\n" . $canonicalQueryString . "\n" . $canonicalHeader;
// Signing the canonical request using key with sha-256 algorithm.
if (empty($YopRequest->secretKey)) {
error_log("secretKey must be specified");
}
extension_loaded('openssl') or die('php需要openssl扩展支持');
$private_key = $YopRequest->secretKey;
$private_key = "-----BEGIN RSA PRIVATE KEY-----\n" .
wordwrap($private_key, 64, "\n", true) .
"\n-----END RSA PRIVATE KEY-----";
$privateKey = openssl_pkey_get_private($private_key);// 提取私钥
($privateKey) or die('密钥不可用');
$signToBase64 = "";
// echo "tyuiop".$canonicalRequest;
openssl_sign($canonicalRequest, $encode_data, $privateKey, "SHA256");
openssl_free_key($privateKey);
$signToBase64 = Base64Url::encode($encode_data);
$signToBase64 .= '$SHA256';
$headers['Authorization'] = "YOP-RSA2048-SHA256 " . $protocolVersion . "/" . $appKey . "/" . $timestamp . "/" . $EXPIRED_SECONDS . "/" . $signedHeaders . "/" . $signToBase64;
if ($YopRequest->config->debug) {
var_dump("authString=" . $authString);
var_dump("canonicalURI=" . $canonicalURI);
var_dump("canonicalQueryString=" . $canonicalQueryString);
var_dump("canonicalHeader=" . $canonicalHeader);
var_dump("canonicalRequest=" . $canonicalRequest);
var_dump("signToBase64=" . $signToBase64);
}
$YopRequest->headers = $headers;
}
public function __set($name, $value)
{
$this->$name = $value;
}
public function __get($name)
{
return $this->$name;
}
public static function get($methodOrUri, $YopRequest)
{
$content = YopRsaClient::getForString($methodOrUri, $YopRequest);
$response = YopRsaClient::handleRsaResult($YopRequest, $content);
return $response;
}
public static function getForString($methodOrUri, $YopRequest)
{
$YopRequest->httpMethod = "GET";
$serverUrl = YopRsaClient::richRequest($methodOrUri, $YopRequest);
$serverUrl .= (strpos($serverUrl, '?') === false ? '?' : '&') . $YopRequest->toQueryString();
self::SignRsaParameter($methodOrUri, $YopRequest);
$response = HttpRequest::curl_request($serverUrl, $YopRequest);
return $response;
}
public static function post($methodOrUri, $YopRequest)
{
$content = YopRsaClient::postString($methodOrUri, $YopRequest);
$response = YopRsaClient::handleRsaResult($YopRequest, $content);
return $response;
}
/**
* @param $methodOrUri
* @param $YopRequest
* @return type
*/
public static function postString($methodOrUri, $YopRequest)
{
$YopRequest->httpMethod = "POST";
$serverUrl = YopRsaClient::richRequest($methodOrUri, $YopRequest);
self::SignRsaParameter($methodOrUri, $YopRequest);
$response = HttpRequest::curl_request($serverUrl, $YopRequest);
return $response;
}
/**
* @param $YopRequest
* @param $forSignature
* @return string
*/
public static function getCanonicalQueryString($YopRequest, $forSignature)
{
if (!empty($YopRequest->jsonParam)) {
return "";
}
$ArrayList = array();
$StrQuery = "";
foreach ($YopRequest->paramMap as $k => $v) {
if ($forSignature && strcasecmp($k, "Authorization") == 0) {
continue;
}
array_push($ArrayList, $k . "=" . rawurlencode($v));
}
sort($ArrayList);
foreach ($ArrayList as $kv) {
$StrQuery .= strlen($StrQuery) == 0 ? "" : "&";
$StrQuery .= $kv;
}
return $StrQuery;
}
/**
* @param $headers
* @param $headersToSign
* @return arry
*/
public static function getHeadersToSign($headers, $headersToSign)
{
$ret = array();
if ($headersToSign != null) {
$tempSet = array();
foreach ($headersToSign as $header) {
array_push($tempSet, strtolower(trim($header)));
}
$headersToSign = $tempSet;
}
foreach ($headers as $key => $value) {
if ($value != null && !empty($value)) {
if (($headersToSign == null && isDefaultHeaderToSign($key)) || ($headersToSign != null && in_array(strtolower($key), $headersToSign) && $key != "Authorization")) {
$ret[$key] = $value;
}
}
}
ksort($ret);
return $ret;
}
/**
* @param $header
* @return bool
*/
public static function isDefaultHeaderToSign($header)
{
$header = strtolower(trim($header));
$defaultHeadersToSign = array();
array_push($defaultHeadersToSign, "host");
array_push($defaultHeadersToSign, "content-type");
return strpos($header, "x-yop-") == 0 || in_array($defaultHeadersToSign, $header);
}
/**
* @param $headers
* @return string
*/
public static function getCanonicalHeaders($headers)
{
if (empty($headers)) {
return "";
}
$headerStrings = array();
foreach ($headers as $key => $value) {
if ($key == null) {
continue;
}
if ($value == null) {
$value = "";
}
$key = HttpUtils::normalize(strtolower(trim($key)));
$value = HttpUtils::normalize(trim($value));
array_push($headerStrings, $key . ':' . $value);
}
sort($headerStrings);
$StrQuery = "";
foreach ($headerStrings as $kv) {
$StrQuery .= strlen($StrQuery) == 0 ? "" : "\n";
$StrQuery .= $kv;
}
return $StrQuery;
}
/**
* @param $methodOrUri
* @param $YopRequest
* @return YopResponse
*/
public static function upload($methodOrUri, $YopRequest)
{
$content = self::uploadForString($methodOrUri, $YopRequest);
$response = self::handleRsaResult($YopRequest, $content);
return $response;
}
public static function uploadForString($methodOrUri, $YopRequest)
{
$YopRequest->httpMethod = "POST";
$serverUrl = self::richRequest($methodOrUri, $YopRequest);
self::SignRsaParameter($methodOrUri, $YopRequest);
$response = HttpRequest::curl_request($serverUrl, $YopRequest);
return $response;
}
static public function richRequest($methodOrUri, $YopRequest)
{
if (strpos($methodOrUri, $YopRequest->config->serverRoot)) {
$methodOrUri = substr($methodOrUri, strlen($YopRequest->config->serverRoot) + 1);
}
$serverUrl = $YopRequest->serverRoot;
$serverUrl .= $methodOrUri;
preg_match('@/rest/v([^/]+)/@i', $methodOrUri, $version);
if (!empty($version)) {
$version = $version[1];
if (!empty($version)) {
$YopRequest->setVersion($version);
}
}
$YopRequest->setMethod($methodOrUri);
return $serverUrl;
}
static public function handleRsaResult($YopRequest, $content)
{
$sign = trim($content['header']['x-yop-sign']);
$signStr = $content['content'];
$signStr = self::trimall($signStr);
$response = new YopResponse();
$jsoncontent = json_decode($content['content']);
if(empty($sign)){
return $content['content'];
}
if (!empty($jsoncontent->result)) {
$response->state = "SUCCESS";
$response->result = $jsoncontent->result;
$response->requestId = $YopRequest->requestId;
// $signStr=$jsoncontent->result;
} else {
$response->state = "FAILURE";
$response->requestId = $jsoncontent->requestId;
$response->error->code = $jsoncontent->code;
$response->error->message = $jsoncontent->message;
$response->error->subCode = $jsoncontent->subCode;
$response->error->subMessage = $jsoncontent->subMessage;
// $signStr = $content['content'];
}
$response->validSign = YopRsaClient::isValidRsaResult($signStr, $sign, $YopRequest->yopPublicKey);
return $response;
}
//去空格换行符
static public function trimall($str){
$qian=array(" "," ","\t","\n","\r");
return str_replace($qian, '', $str);
}
#header sign 验签
public static function isValidRsaResult($result, $sign, $public_key)
{
// $result=json_encode($result,320);
$str = "";
if ($result == null || empty($result)) {
$str = "";
} else {
$str .= trim($result);
}
;
$public_key = "-----BEGIN PUBLIC KEY-----\n" .
wordwrap($public_key, 64, "\n", true) .
"\n-----END PUBLIC KEY-----";
$pu_key = openssl_pkey_get_public($public_key);
// $str=str_replace("\\","",str_replace("\\n","",$str));
$str= self::trimall($str);
$str= trim($str, '"');
$res = openssl_verify($str,Base64Url::decode($sign), $pu_key,"SHA256"); //验证
openssl_free_key($pu_key);
if ($res == 1) {
echo "验签成功";
return true;
} else {
echo "验签失败";
return false;
}
}
}