摘要:如何獲取受支持的算法清單,請參見。要進行哈希運算的消息。使用生成信息摘要時所使用的密鑰。設置為輸出原始二進制數據,設置為輸出小寫進制字符串。
介紹一下問題的背景:
本人一枚小小PHPer,有一天公司的Java找到我,讓我幫忙寫一個接口的Demo,心想:‘最喜歡寫接口了,來來來來!’,于是Java就帶著Java版Demo來了,大概看了一遍,具體涉及以下幾點:(不想了解的看最后一部分,就好了,那是中心思想)
md5加密:
java中定義hashMap,儲存userid,再使用toJSONString將其轉換成Json串,再將Json使用md5Hex加密,再放入hashMap中
map參數格式轉換:
將map中的數據轉換成String,對key,value進行數據拼接,拼接成字符串,此字符串具體要求如下:
‘按照參數名ASCII碼從小到大排序,使用URL鍵值對的格式(即key1=value1&key2=value2…)構造成字符串signPlainText’
hash_hmac簽名驗證:
這個沒什么說的,PHP中有hash_hmac函數
談論一下遇到的坑:本PHPer比較渣渣,不知道Java中的hashMap是用來做啥的,但我知道,它最后做了一件事:JSONObject.toJSONString(body),沒錯,轉換成字符串了,所以有了以下代碼:(不負責的貼圖,不知道正確與否)
md5加密Java版
Mapbody = new HashMap<>(); body.put("userId", userId); //post請求body為json格式,將json格式進行md5加密 String postBody = JSONObject.toJSONString(body); String bodyMd = DigestUtils.md5Hex(postBody);
PHP版
$body = ["userId"=>$userId]; $postbody = json_encode($body); $bodyMd = md5($postbody);
上邊我們之間應該是在做一件事請吧?應該是的,反正都是轉成了Json,轉成了Md5
接下來就是map轉換string了,再貼兩段代碼:(不負責的貼,不知道正確與否)
(按照參數名ASCII碼從小到大排序,使用URL鍵值對的格式(即key1=value1&key2=value2…)構造成字符串signPlainText)
Java版
MapresultMap = new TreeMap<>(); for (Map.Entry entry : map.entrySet()) { String key = (String) entry.getKey(); Object value = entry.getValue(); if (StringUtils.isEmpty(key) || value == null) { continue; } resultMap.put(key, value); } StringBuilder buff = new StringBuilder(); for (Map.Entry entry : resultMap.entrySet()) { buff.append(entry.getKey()).append("=").append(entry.getValue()).append("&"); } String signPlanText = buff.toString(); if (StringUtils.isNotEmpty(signPlanText)) { signPlanText = signPlanText.substring(0, signPlanText.length() - 1); } return signPlanText;
PHP版
$signPlanText = ""; ksort($params); foreach ($params as $key => $param){ if(empty($key) || $param == null){ continue; } $signPlanText .= $key."=".$param."&"; } if($signPlanText){ $signPlanText = substr($signPlanText,0,strlen($signPlanText)-1); } return $signPlanText;
遇到的問題: 因為Java中Treemap是有序的,按照自然值進行排序,但PHP中好像沒有這樣一個東西,所以決定使用Ksort來進行排序,不知道是否正確!應該是正確的吧?各位大神拍磚~
HmacSHA256簽名驗證:Java版
String signature = ""; try { Mac sha256HMAC = Mac.getInstance(HMACSHA256); SecretKeySpec secretkey = new SecretKeySpec(appSecret.getBytes(StandardCharsets.UTF_8), HMACSHA256); sha256HMAC.init(secretkey); byte[] bytes = sha256HMAC.doFinal(plainText.getBytes(StandardCharsets.UTF_8)); signature = Base64.encodeBase64URLSafeString(bytes); } catch (Exception e) { e.printStackTrace(); } return signature;
PHP版( 呀?看起來是不是沒有問題?)
$hmac_sha256_str = base64_encode(hash_hmac("sha256", $signPlanText, $appSecret)); $signature = urlencode($hmac_sha256_str); return $signature;
還在想,PHP這么點代碼就解決了?不愧是世界上最好的語言’,(大佬們,我加引號了)
23:35分終于翻譯完以上Java代碼,放一首歌,美美的睡覺,心想明天可以美美的交工~ (滴滴滴滴滴滴等待~地理地理等待~~)
坑來了,運行上邊代碼,你會發現,接口提示簽名錯誤!!錯誤一直是錯誤!!為什么呢???明明是一樣的啊!百思不得其解!!
繼續往下看···
再看PHP文檔中的hash_hmac的聲明:
string hash_hmac ( string $algo , string $data , string $key [, bool $raw_output = FALSE ] ) algo 要使用的哈希算法名稱,例如:"md5","sha256","haval160,4" 等。 如何獲取受支持的算法清單,請參見 hash_algos()。 data 要進行哈希運算的消息。 key 使用 HMAC 生成信息摘要時所使用的密鑰。 raw_output 設置為 TRUE 輸出原始二進制數據, 設置為 FALSE 輸出小寫 16 進制字符串。
在Java中sha256HMAC后得到的值為二進制,So,PHP也要轉換為二進制,所以改進為以下代碼:
hash_hmac("sha256", $signPlanText, $appSecret,true);//由此生成出的為二進制格式
這還沒完,最重要的出現了:
java中Base64.encodeBase64URLSafeString(bytes) 會將 特殊字符‘+/’替換為"-_",會將‘=’去掉
但是!!PHP不會!!! PHP 沒有提供url安全的base64編碼函數,需要自己手動去擼!還是自己水平不夠
So,出現了以下代碼,也是最終的解決方案:
/** * 簽名驗證 */ public static function generateSHASign($signPlanText,$appSecret){ $signature = self::base64UrlEncode(hash_hmac("sha256",$signPlanText, $appSecret, true)); return $signature; } /** * 替換特殊符號 */ public static function base64UrlEncode($str){ return rtrim(strtr(base64_encode($str),"+/","-_"),"="); }
這時,你會發現,簽名正確,原來生活如此美好、怪我太年輕
同時有朋友說:
1.是有兩套不相同的標準,Ios一套,Java一套
2.在PHP中url_encode這個函數,分兩種: urlencode 和 rawurlencode
兩者的差異:urlencode和rawurlencode兩個方法在處理字母數字,特殊符號,中文的時候結果都是一樣的,唯一的不同是對空格的處理,urlencode處理成“+”,rawurlencode處理成%20
總結下來就是:
php的base64_encode和base64_decode用來轉換url是不符合要求,所以需要自己實現方法
base64url_decode
public static function base64url_decode($data) { return base64_decode(str_pad(strtr($data, "-_", "+/"), strlen($data) % 4, "=", STR_PAD_RIGHT)); }
base64url_encode
public static function base64url_encode($data) { return rtrim(strtr(base64_encode($data), "+/", "-_"), "="); }
終是曉夢迷了蝶,你是恩賜也是劫!
文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/73133.html
摘要:如何獲取受支持的算法清單,請參見。要進行哈希運算的消息。使用生成信息摘要時所使用的密鑰。設置為輸出原始二進制數據,設置為輸出小寫進制字符串。 介紹一下問題的背景: 本人一枚小小PHPer,有一天公司的Java找到我,讓我幫忙寫一個接口的Demo,心想:‘最喜歡寫接口了,來來來來!’,于是Java就帶著Java版Demo來了,大概看了一遍,具體涉及以下幾點:(不想了解的看最后一部分,就好...
摘要:我們做程序的時候,加密解密是繞不開的話題,使用開發應用的時候,都內置了哪些有關加密解密安全方便的支持那本文將為你揭曉。函數聲明為存在著第三個參數,比如我們可以傳遞會員的等,這樣此信息將和一起作為加密解密的鑰匙。 我們做程序的時候,加密解密是繞不開的話題,使用yii2開發應用的時候,都內置了哪些有關加密解密(安全)方便的支持那?本文將為你揭曉。 相關環境 操作系統及IDE macOS ...
摘要:另外說到請求對方接口的問題,對方要求傳遞一個參數過去,比如結果提示但是沒問題于是對參數再進行一次但對方有時候接受的參數解析出錯于是有了如下處理傳遞時也改成安全 最近接一個項目,需要調用對方接口生成 token 但只提供了 node 版,源代碼如下 //https://blog.zhengxianjun.com/2015/05/javascript-crypto-js/ npm inst...
摘要:個人博客本文原地址最近的項目中,需要用到畫圖和圖片拼接效果,這里是一些開發過程里用到的一些點還有就是一些踩過的坑。通過生成圖片格式,為前端所使用。需要注意的是前端得到的額數據里包含有回車字符,需要特殊處理才可以正確顯示圖片。 個人博客 https://duanruilong.github.io/blog/本文原地址https://duanruilong.github.io/blog/2...
閱讀 1181·2023-04-26 00:34
閱讀 3354·2023-04-25 16:47
閱讀 2119·2021-11-24 11:14
閱讀 3104·2021-09-26 09:55
閱讀 3712·2019-08-30 15:56
閱讀 3215·2019-08-29 16:57
閱讀 1909·2019-08-26 13:38
閱讀 2667·2019-08-26 12:22