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
PHP

This file contains invisible Unicode characters!

This file contains invisible Unicode characters that may be processed differently from what appears below. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to reveal hidden characters.

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