回眸曾經的項目,與第三方支付相關,所帶來的溝通問題

導讀

筆者在校期間,通過自學java。學校裏也開過這門課,但是,講的都是一些基礎,比如java的表達式、基本類型、自定義類型等等。也都是很基礎的東西,就連lambda表達式都沒有。然而,讓我們交的作業,是用java-web開發出的網站。我當時做的是與圖書共享相關的網站。當時滿腔熱血的想着去創業,但是,因爲自身還沒離開學校,社會經驗不是特別足,於是,這件事就擱淺了。

去年六月份畢業,參加了班級的散夥飯後,大家也都各奔東西。但大部分從事軟件開發的行業,有些人進入外包公司,有些人進入了遊戲公司。不管進入到什麼行業,在最初的一段時間中,遇到一個教你的人很重要。這樣,你可以學校到很多東西。當然,你自己也得努力學習。

我依稀記得第一次做項目,那個項目做得真是一塌糊塗,權當我個人練手用了。對於個人來說,成長是非常快的,但是,對於企業來說,這是一種損失。真的是損失。因爲,企業讓你來做事,不是讓你來試驗的。自從第一個項目失敗後,也不能說失敗吧,至少做得不夠完美。項目沒有達到鬆散耦合的程度。我在開發的過程中,遇到了各種各樣的問題,在他人的幫助下,慢慢地適應了開發強度。

當時,我給自己定義的是java後端開發工程師,因而,接口都是通過postman來測試。我們的持久層使用的hibernate框架,於是,仿照hibernate寫個框架,參考我的博客:模仿hibernate框架,詳解hibernate部分方法設計;同時使用spring容器集合該框架,於是,仿照了spring寫個框架,可以參考我的博客:模擬spring框架,深入講解spring的對象的創建;數據過濾的框架是Apache下的beanutils框架,於是,模擬beanutils寫個框架,參看我的博客:只因數據過濾,方可模擬beanutils框架

框架能寫的出來,而這只是java端的,我並不知道前端的一些情況,比如前端和後端是如何進行數據交互的,前端如何在頁面展示數據等等。於是,下載了前端的頁面。我們前端的頁面放置在SVN上,後端代碼放置在git上。自己慢慢地根據前端頁面去摸索,神奇地是能夠展示出數據。帶我的人看我做的還不錯,於是,教我前後端一起開發。

我們這個是前後端分離的,前端調用後端的接口。在學校裏面也學過前端的一些知識,比如CSS3、HTML5,jQuery,JavaScript等等,那時並不是項目開發,有些東西只是自己弄着玩的。但公司項目的開發和自己開發完全不是一回事,需要掌握很多的前端知識。

不久,做了個完整的前端項目,因爲有學校的經驗,有些東西很快就掌握了,但是,其他很多東西還不怎麼會,真的很腦大。但隨着項目的深入,才發現自己在學校學的知識,還是遠遠地不夠項目開發所用的。於是,不斷地充電,不斷地向前輩的學習,現在,前端的很多東西也知道了。

現在,回過頭看我寫的前端代碼,再看前輩給我寫的前端代碼,我發現我那時寫的真的垃圾,可以用不堪入目這個詞來形容。但是,當時設計的頁面還是蠻酷的,也得到了老闆的認可。這是我值得驕傲的事。

我不斷地嘗試前後端的開發,也從中知道了vue.js,bootstrap,jQuery、echart等前端框架。也知道了本地ip和局域網ip的區別,以及如何用小米球做本地調試。從而更知道了,如何實現前後端分離。我越來越相信這句話,只要你努力,就會有人幫助你。

隨着時間地推進,老闆接了一個項目,就是圖書共享的項目。我當時聽到這個項目後,我就感覺到有點難過。這和我畢設所做的項目思想是一致的,如果,我當時能夠勇敢一點,也許,我就推廣我的這個項目了。但是,我沒有。

世界就是這麼殘酷,不允許你有絲毫地猶豫。於是,老闆再接下一個項目後,項目名爲雲碼兌換平臺。用戶收到某家公司給的代幣(福利),拿到代幣到這個平臺上兌換成錢。錢可以存儲在自己的餘額中,這就相當於微信錢包,餘額可以提現到銀行卡的中。也可以使用餘額來購買商品。這分爲企業錢包和個人錢包,企業錢包和個人錢包是不一樣的。

我沒做個類似項目,於是,就接過來做了。老闆說這個項目對我來說,難度係數還是比較大的。我就下定決心把這個項目給做好,因爲我知道可以從這個項目學到很多東西。我們的第三方支付平臺是連連支付,杭州的一家公司。

支付

這個項目可以說沒有任何人帶我,完全由我自己參考連連給的文檔,邊學習邊嘗試着去開發。這樣,也培養了我調用第三方接口,參讀他們文檔的能力。可以說,未嘗不是一種收穫呢?

我們老總說過年前夕,只做支付相關的業務,也就是,用戶提交代幣兌換金額的申請,後臺管理員接收到這個申請後,從後臺給用戶打款。如圖所示:

clipboard.png

後臺管理員點擊批量打款時,服務端會做數據的篩選,曬選出狀態爲待轉讓的客戶打款,其他情況下一律不打款。就這麼一個小小的支付按鈕,其內部涉及太多的知識點。

我之所以害怕,是因爲對未知的恐懼。一開始做支付非常難,其實,做完之後,也沒有我想像的那麼難。但是,我還是需要做一些準備工作。比如,下載連連支付的SDK。但要考慮到SDK是什麼SDK?SDK分爲兩種,一種是應用到java開發中,一種是應用到Android或iOS開發中。因爲,連連那邊沒有將其區分開來,從而造成錢包項目的延誤。這個會在下文提到。

下載好連連支付的SDK後,我們通過maven創建項目,使用的是阿里雲的中央倉庫,其並不存在連連SDK。因而,我們需要配置本地的Maven庫。這個網上都有教程的,我在這裏就不細說了。

配置好了SDK後,我們需要了解簽名機制,連連使用的RSA簽名機制,如圖所示:

RSA簽名原理

至於連連爲什麼使用RSA簽名,可以參考我的這篇博客:支付與簽名原串的那些事,但選擇排序生成簽名原串

我們將生成的pkcs8格式的公鑰上傳到連連商戶站,再從連連的商戶站下載其連連公鑰。私鑰用以加簽,公鑰用以驗籤,這用以提高數據的安全性。

私鑰怎麼加簽?每個公司的加簽方式是不一樣的,支付寶有支付寶的加簽方式,微信有微信的加簽方式。這裏,我就說說連連支付的加簽方式。我們在向連連發送支付請求前,需要封裝我們的請求參數,將請求參數以一定格式的方式存儲,這就是簽名原串,如圖所示:

簽名原串

將簽名原串和我們的pkcs8格式的私鑰共同加密,這就調用到jdk數字簽名的這幾個包:

import java.security.KeyFactory;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;

得到加簽後的簽名字符串,再調用連連支付的LianLianPaySecurity.encrypt(JSON.toJSONString(preq), PaymentConstant.LIAN_PUBLIC_RSA_KEY);加密算法,該算法有兩個參數,一個是包括簽名的氫氣參數,一個是下載下來的連連公鑰。

如果請求連連支付成功的話,其會返回一段字符串,該字符串包含連連的簽名原串、私鑰簽名串等其他信息。連連那邊的簽名串的加簽方式,和我們這邊的是一樣的。我們從連連下載下來的連連公鑰,其公鑰也是其由私鑰生成而來。其將請求參數封裝成簽名原串,將私鑰和簽名原串共同加簽成簽名串。

因而,我們這邊拿到了連連的簽名原串和簽名串之後,就要進行驗簽了。怎麼驗籤呢?我們這個時候,就用到了從連連的商戶站下載的連連公鑰了,如代碼所示:

 /**
 * Created By zby on 17:28 2018/12/18
 * RSA簽名驗證
 * <p>
 * * @param reqObj: The obtained asynchronous notification body
 * * @param rsa_public: The public key provided by LianLian
 */
public static boolean checkSignRSA(String response) {
    logger.info("【響應參數】申請付款的響應參數爲:" + response);
    if (StringUtils.isBlank(response)) {
        return false;
    }
    JSONObject reqObj = JSONObject.parseObject(response);
    String lianPubkey = PaymentConstant.LIAN_PUBLIC_RSA_KEY;
    String lianSigned = reqObj.getString("sign");
    String lianSignSrc = genSignData(reqObj);
    ifNullThrow(lianPubkey, ResultCodeEnum.NOT_CONFIG_LIAN_PUBLIC_KEY_VALUE);
    try {
        if (TraderRSAUtil.checksign(lianPubkey, lianSigned, lianSignSrc)) {
            return true;
        } else {
            return false;
        }
    } catch (Exception e) {
        return false;
    }
}

底部調用的是TraderRSAUtil.checksign這個方法,其內部如代碼所示:

  /**
 * 簽名驗證
 *
 * @param lianPubkey  下載好的連連公鑰
 * @param lianSignSrc 連連的簽名原串,也就是將返回串封裝成jsonObject
 * @param lianSigned  連連加密簽名簽名,包括簽名原串+私鑰
 * @return
 */
public static boolean checksign(String lianPubkey, String lianSigned,
                                String lianSignSrc) {
    try {
        //【1】獲取公鑰
        //獲取KeyFactory,指定RSA算法
        KeyFactory keyFactory = KeyFactory.getInstance(PaymentConstant.SIGN_TYPE);
        //將BASE64編碼的公鑰字符串進行解碼
        BASE64Decoder decoder = new BASE64Decoder();
        //將BASE64解碼後的字節數組,構造成X509EncodedKeySpec對象,生成公鑰對象
        PublicKey publicKey = keyFactory.generatePublic(new X509EncodedKeySpec(decoder.decodeBuffer(lianPubkey)));
        byte[] signed = decoder.decodeBuffer(lianSigned);
        //【2】使用公鑰,進行驗籤
        //獲取Signature實例,指定簽名算法(與之前一致)
        Signature signature = Signature.getInstance(PaymentConstant.MD5_WITH_RSA);
        //加載公鑰
        signature.initVerify(publicKey);
        //更新原數據
        signature.update(lianSignSrc.getBytes(BaseConstant.CHARSET));
        //公鑰驗籤(true-驗籤通過;false-驗籤失敗)
        return signature.verify(signed);
    } catch (Exception e) {
        e.printStackTrace();
    }
    return false;
}

這就是一個支付的流程,不論是任何第三方支付,其都要有加簽和驗籤,因爲,這是最基本的安全機制。只不過,各個公司的加簽和驗籤方式有所不同而已。

當然,有些東西就沒必要使用RSA加簽和驗簽了,比如連連那邊的綁定銀行卡的業務,其加簽方式就是用MD5加簽的。但是,支付涉及到了金額,這個,只要與錢相關的業務。都需要謹慎處理,也許,RSA不是最好的加密方式,但就目前而言,其還是比較安全的。

錢包

爲什麼要做錢包呢?做任何事都要有其目的。

我們做的是福利平臺。屆時,許多商戶會入駐該平臺,給其用戶提供不同的優惠卡或者錢,比如流量充值卡、話費充值卡,中石油的加油卡等。不同商戶提供不同的(虛擬)商品,不同的商品對應多少錢,比如話費卡30元,流量卡30元等。商戶需要在錢包中充錢(充值),便於用戶兌換。

用戶拿到這些卡消費時,商戶的錢包裏的錢會減少。用戶可以通過代幣兌換這些充值卡,也可以通過代幣兌換錢,商戶的錢就會變少,而用戶的錢包的錢增加,其可以提現到銀行卡(提現),也可以購買其他產品(支付);在購買時,錢包餘額不夠,可以充值到連連錢包(充值)。如果已經購買了,也可以,申請退款(退款)。 同時,也可以查看提現記錄(提現查詢),支付記錄(支付查詢);

總的來說,電子錢包可以存儲用戶的金額,相當於微信支付中的餘額,也相當於我們現實中的錢包。用戶可以支配錢包金額(餘額),但並非任意支配。因爲用戶支配的額度不能超過錢包的額度。

今年都到了三月二十四號了,我們的錢包也已經就開始做了。但是,可能,我們這邊的產品經理和連連那邊的業務沒有溝通好,其所提供給我們的web組件全部是走他們的頁面。我當時問他們的頁面支不支持響應式佈局,他們堅決地回答說不支持。如圖所示:

提現頁面

這在PC端的瀏覽器中看,界面還是可以的,但是,如果用手機端看的話,其會非常的彆扭,如圖所示:

手機端的提現界面

你會發現,這簡直不能使用。我當時和對方說,這種效果的用戶體驗不好。他們說我們這邊提供的了手機端的SDK組件,我看了他們給的SDK組件,其完全是Android開發和iOS開發的SDK組件。他們以爲我們用的測試Android開發的,而我們這是微信公衆號,是嵌入在微信中的h5頁面,自然是不能使用的。

這就是產品經理和業務沒有溝通好帶來的誤會,產品經理說他們那邊的業務不懂技術。他們那邊的業務以爲SDK就是SDK,不區分是不是Android和iOS,還是服務端java的SDK。業務也沒有問他們那邊的技術。因而,浪費了這一個月的時間。我們這是從開年就開始做錢包了,做到現在就遇到了這個問題。所以,很多東西都要重新做。

對於企業來說,這是一個損失。但對於我個人來說,這是一種成長。不論是技術方面,還是與人溝通方面,都是一種成長。

我們後來和他們說,web組件走不通了,能不能通過API的方式自定義界面,他們說他們這邊也是提供的,不過,是最近剛開放的API的接口。我們這邊的產品經理非常生氣,說你們那邊沒有的話,就早點和我們說嗎,免得浪費我們的時間。

我在開發的起始階段,看了他們的SDK,也有和對方溝通。我說我們這是公衆號開發,你們這個SDK好像有問題,他們那邊說你可以使用web組件,當時,也沒有說到這個API的接口。

溝通問題

出現上述的問題,也不能說是誰的錯。事情已經出了,生氣也沒用。因而,我就從這件事中吸取教訓。凡是,都要先溝通好,比如,就這個SDK的問題。是什麼樣的SDK?嵌入在java中的SDK,還是純安卓的SDK。這個,就需要考慮清楚。溝通是非常重要,如果溝通的不及時,既浪費了人力和物力,也讓雙方都不開心。

因而,以後爲人處事,一定要學會溝通。不過,這對於我來說,也是一次小小的成長吧。在成長的過程中,就會摔跟頭的。但站起來之後,回頭看看絆倒自己的是什麼?是石頭,還是香蕉皮?以後,再遇到這樣的事情,能不能及時的溝通。

祝自己在成長的過程,愈挫愈勇吧。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章