Parcourir la source

调试走通 ticket 的签名认证

shizhongqi il y a 8 mois
Parent
commit
9c42ebbde8

+ 4 - 1
app-ghs/controllers/DeliveryController.php

@@ -29,7 +29,7 @@ class DeliveryController extends BaseController
         'huolala-auth-callback', 'huolala-callback',
         'fengniao-auth-callback', 'fengniao-callback',
         'shunfeng-callback',
-        'dada-callback'
+        'dada-auth-callback', 'dada-callback'
     ];
 
     public function actionList()
@@ -86,6 +86,9 @@ class DeliveryController extends BaseController
             case 'didi':
                 $Auth->didiAuth($mainId, $this->shopId);
                 break;
+            case 'dada':
+                $Auth->dadaAuth($mainId);
+                break;
             default:
                 util::error(-1, $platform . '不存在');
                 break;

+ 0 - 1
common/components/delivery/helpers/HttpClient.php

@@ -80,7 +80,6 @@ class HttpClient
 
                 $status = $response->getStatusCode();
                 $respBody = (string) $response->getBody();
-
                 Yii::info("[HttpClient] GET {$url} {$status} {$respBody}");
 
                 $json = json_decode($respBody, true);

+ 122 - 19
common/components/delivery/platform/dada/Auth.php

@@ -2,6 +2,7 @@
 namespace common\components\delivery\platform\dada;
 
 use common\components\delivery\helpers\HttpClient;
+use common\components\util;
 use Yii;
 
 /**
@@ -38,7 +39,7 @@ class Auth
      */
     public function __construct()
     {
-        $isProduction = getenv('YII_ENV') == 'dev';
+        $isProduction = getenv('YII_ENV') == 'dev'; // TODO
         
         if ($isProduction) {
             // 生产环境配置(需要替换为实际的生产环境凭证)
@@ -87,14 +88,52 @@ class Auth
         $params = [
             'appKey' => $this->appKey,
             'nonce' => $nonce,
-            'sign' => strtoupper($sign),
+            'sign' => $sign,
         ];
         
         // 发送 GET 请求
-        $url = $this->authorizeUrl . 'third/party/ticket';// . '?' . http_build_query($params);
+        $url = $this->authorizeUrl . 'third/party/ticket';
         
         try {
-            $resp = HttpClient::get($url, $params); // $params
+            // 构建完整请求 URL
+            $requestUrl = $url;
+            if (!empty($params)) {
+                $requestUrl .= '?' . http_build_query($params);
+            }
+            Yii::info("\n\n\n\n\n\nrequestUrl: " . $requestUrl);
+
+            // 初始化 cURL
+            $ch = curl_init();
+            
+            // 设置选项
+            curl_setopt($ch, CURLOPT_URL, $requestUrl);
+            curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
+            curl_setopt($ch, CURLOPT_HEADER, false);
+            curl_setopt($ch, CURLOPT_TIMEOUT, 15);
+            curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
+            curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
+            curl_setopt($ch, CURLOPT_HTTPHEADER, [
+                'Content-Type: application/json'
+            ]);
+
+            // 执行请求
+            $response = curl_exec($ch);
+            $error = curl_error($ch);
+            curl_close($ch);
+
+            // 检查错误
+            if ($error) {
+                throw new \Exception('cURL Request Error: ' . $error);
+            }
+
+            // 解析响应
+            $resp = json_decode($response, true);
+            if (json_last_error() !== JSON_ERROR_NONE) {
+                // 如果解析失败,可能是非 JSON 响应
+                // throw new \Exception('Invalid JSON Response: ' . $response);
+                Yii::error('Invalid JSON Response: ' . $response);
+                util::fail('请求达达获取ticket失败');
+            }
             
             // 检查响应状态,返回 ticket
             if (isset($resp['result']) && !empty($resp['result'])) {
@@ -137,33 +176,73 @@ class Auth
             'appSecret' => $this->appSecret,
         ];
         
-        // 第一步:按键排序
-        ksort($signParams);
-        // 第一步:按值排序且不改变key
+        // 第一步
+        // 按键排序
+        //ksort($signParams, SORT_STRING);
+        // 按值排序且不改变key
         //asort($signParams);
-        //sort($signParams, SORT_STRING);
+        sort($signParams, SORT_STRING);
        
         
         // 第二步:拼接所有参数值
         $signString = implode('', $signParams);
-        //$signString = $signString . $this->appSecret;
+        
         // 第二步:拼接 key 和 value
-//        $signString = '';
-//        foreach ($signParams as $key => $value) {
-//            $signString .= $key . $value;
-//        }
-//        $signString = $signString . 'appSecret' . $this->appSecret;
+        // $signString = '';
+        // foreach ($signParams as $key => $value) {
+        //     $signString .= $key . $value;
+        // }
+        // $signString = $signString;
         
         // 第三步:SHA1 加密
         $hex = sha1($signString);
 
-        $len = 36;
-        if ($len < strlen($hex)) {
-            $hex = substr($hex, 0, $len);
-        }
+        // $len = 36;
+        // if ($len < strlen($hex)) {
+        //     $hex = substr($hex, 0, $len);
+        // }
+
+        //return strtoupper(substr($hex, 0, 36));
+        //return strtoupper($hex);
         return $hex;
     }
 
+    /**
+     * 生成获取授权码请求的签名
+     * 
+     * 签名算法:
+     * 1. 参与签名的参数值按字典排序:appKey、appSecret、nonce
+     * 2. 拼接参数值
+     * 3. SHA1 加密
+     * 
+     * @param string $nonce 随机数
+     * @return string SHA1 签名
+     */
+    function generateTicketSign_234($nonce)
+    {
+        // 1. 按字段名升序拼接
+        $map = [
+            'appKey'    => $this->appKey,
+            'appSecret' =>$this->appSecret,
+            'nonce'     => $nonce,
+        ];
+        ksort($map, SORT_STRING);          // 按 key 升序
+       
+        $raw = '';
+        foreach ($map as $k => $v) {
+            $raw .= $k . $v;               // 不要加 & = 空格
+        }
+        //$raw = implode('', $map);
+
+        // 2. SHA1 得到 40 位 16 进制(小写)
+        $sha1 = sha1($raw, false);         // 第二个参数=false 返回十六进制字符串
+
+        // 3. 转大写 + 截前 36 位
+        //return strtoupper(substr($sha1, 0, 36));
+        return strtoupper($sha1);
+        return sha1($raw);
+    }
+
     private function newGenerateTicketSign($nonce)
     {
         // 参与签名的参数
@@ -223,7 +302,7 @@ class Auth
         $nonce = $this->generateNonce();
         
         // 生成签名
-        $sign = $this->generateSign($ticket, $nonce, $shopId);
+        $sign = $this->generateAuthSign($ticket, $nonce, $shopId);
         
         // 构建授权链接参数
         $params = [
@@ -246,6 +325,30 @@ class Auth
         
         return $this->authorizeUrl . 'third/party/oauth' . '?' . http_build_query($params);
     }
+
+    private function generateAuthSign($ticket, $nonce, $shopId = '')
+    {
+        // 参与签名的参数
+        $signParams = [
+            'appKey' => $this->appKey,
+            'ticket' => $ticket,
+            'nonce' => $nonce,
+            'appSecret' => $this->appSecret,
+        ];
+
+        if($shopId!=''){
+            $signParams['shopId'] = $shopId;
+        }
+
+        // 第一步
+        sort($signParams, SORT_STRING);
+        // 第二步:拼接所有参数值
+        $signString = implode('', $signParams);
+        // 第三步:SHA1 加密
+        $hex = sha1($signString);
+
+        return $hex;
+    }
     
     /**
      * 生成随机数(nonce)

+ 4 - 4
common/components/delivery/platform/dada/Dada.php

@@ -25,7 +25,7 @@ class Dada
      */
     public function __construct()
     {
-        $isProduction = getenv('YII_ENV') == 'production';
+        $isProduction = getenv('YII_ENV') == 'dev'; // TODO
 
         if ($isProduction) {
             // 生产环境配置(需要替换为实际的生产环境凭证)
@@ -98,15 +98,15 @@ class Dada
         // 拼接参数字符串
         $str = '';
         foreach ($params as $key => $value) {
-            // 跳过空值
-            if ($value === '' || $value === null) {
+            // 跳过 null 值,但保留空字符串(如 body 为空时)
+            if ($value === null) {
                 continue;
             }
             $str .= $key . $value;
         }
 
         // 加上 app_secret
-        $str .= $this->appSecret;
+        $str = $this->appSecret . $str . $this->appSecret;
 
         // MD5 加密,返回 32 位大写字符串
         return strtoupper(md5($str));

+ 1 - 0
common/components/delivery/services/AuthService.php

@@ -1,6 +1,7 @@
 <?php
 namespace common\components\delivery\services;
 
+use Yii;
 use bizHd\shop\classes\ShopClass;
 use common\components\util;