時間:2015-02-26 作者:Abyssly 來源:Abyssly Blog
最近由於工作需要,接觸了微信公眾號的開發。業務上要求綁定微信用戶和系統用戶,以便用戶在一次綁定后能夠通過系統用戶的身份去使用一些功能。我關注的招行信用卡公眾號實現了這個功能,所以估計還是可行的,在網上搜索了一下,發現這個問題沒什么好的答案,很多都說取不到微信用戶名實現不了,甚至有說實現了這個功能的應該是與微信有內部合作的。
搜索無果,遂自己動手實驗,后發現其實完全可以的,看來實踐才是檢驗真理的唯一標准,方案上也很簡單,我分幾點來說。
用OpenID綁定即可
微信接口中雖然沒給用戶的微信賬號,但給了用戶的OpenID,這個OpenID對一個公眾號是唯一的,測試也證明不會改變,也就是說同一個微信號和同一個公眾號交互,我們得到的OpenID是不會變的,因此,可以用OpenID作為微信用戶的身份標識。
如何綁定
俗話說,沒吃過豬肉還沒見過豬跑。看招行信用卡公眾號是如何做的,在微信里面給用戶一個驗證鏈接,用戶點擊鏈接,微信會用內嵌的瀏覽器打開這個鏈接,然后就是一般的網頁登錄驗證界面,我們通過HTTP(S)獲取用戶輸入的系統用戶名與密碼,驗證通過后完成綁定。 具體如何生成鏈接和如何傳遞OpenID下面詳述。
如何生成綁定鏈接
綁定涉及到用戶的身份甚至利益,所以需要注意安全性。我們需要綁定的是OpenID和系統用戶,系統用戶名是用戶直接在鏈接頁面輸入后通過HTTP(S)傳給我們的,這沒有問題。OpenID對用戶來說透明,用戶不會傳給我們,我們也只有在用戶在微信中向公眾號發消息時才可獲得OpenID,所以很明顯,OpenID需要包含在生成的鏈接中,至於需不需要對OpenID作加密就看你自己了,我覺得這不重要,更為重要的是要在鏈接中帶上簽名和加上時間戳。因為我們需要確認這個鏈接是由我們服務端生成的,用戶自己或者其他人不能夠偽造出這個鏈接,加上時間戳是為了給這個鏈接一個過期時間,如果不限制過期時間,假設用戶綁定后這個鏈接通過某種方式被別人知道,那么這個人就可以把自己的賬號與用戶的微信號綁定。所以我采取的方法是用OpenID、過期時間再加上一個密鑰生成簽名,生成簽名的方法和微信服務器接口驗證時的簽名方法類似(密鑰最好另選一個只有自己知道的)。
如何傳遞OpenID
有了綁定鏈接,用戶點了綁定鏈接,但這只是第一步,第二步我們需要在用戶在鏈接頁面提交登錄請求后進行驗證,OpenID怎么傳到第二步中呢?有人說了,這還不簡單,在登錄表單中加一個隱藏域放用戶的OpenID一起提交給驗證的Handler不就OK了,那我只能說很遺憾,你前面所做的安全工作都白費了,一旦A用戶的OpenID泄漏,B用戶就可以把自己的賬號與A用戶的微信號綁定了。所以永遠不要相信客戶端提交的東西。我的方法是當用戶點擊生成鏈接后,在鏈接頁載入時,將OpenID存到session中,因為這個session是沒法偽造的(cookie被盜除外),所以只有點擊這個鏈接的用戶的session中才會有鏈接中包含的OpenID。
關於微信服務器簽名多說一句
大家都知道微信公眾號消息接口驗證時微信會向我們服務器發一個GET請求,在其中帶上只有我們和微信服務器知道的簽名,我們在請求處理Handler中會驗證這個簽名,這點大家無異議;消息接口驗證通過后,微信就會把用戶發的消息以POST的方式發給我們,很多人可能會在這里忽視對簽名的檢查,從而給惡意者偽造用戶請求的機會。在微信以POST方式傳遞用戶的消息時,仍然會將簽名信息附在URL參數中,我們在處理每一個POST請求時,第一步還是得像處理消息接口驗證時一樣,去對URL參數中的簽名作驗證,只有簽名驗證通過后才可去取POST的信息。
綁定流程的詳細描述
我在上面說了基本方法,但不夠詳細,導致一些新手朋友還是不清楚具體如何操作,所以我在此嘗試更加詳細地描述整個過程的每一步:
- 數據庫中建立用戶OpenID和系統用戶的綁定關系表,初始時為空。
- 用戶和微信交互時,你可以取到用戶的OpenID。
- 檢查數據表,如發現該OpenID沒有綁定系統用戶,則返回一個鏈接供用戶在微信內嵌瀏覽器中打開,這個鏈接打開后類似於系統用戶登錄界面。
- 關鍵是鏈接的生成,鏈接需要帶3個url參數:
1. 用戶OpenID:因為你需要在綁定頁面中取到是哪個微信用戶想要綁定系統用戶。 2. 時間戳timestamp:這是為了防止鏈接泄漏出去被惡意利用,具體來說就是一個你指定的過期時間,超過這個時間這個鏈接就失效了,用戶只能再次獲取。 3. 簽名signature:這是為了保證此驗證鏈接只有你才可能生成,用戶及第三方均無法偽造。
- 簽名的生成需要你有一個只有你知道的token(密鑰,不要與設置在公眾號里面的token相同),生成簽名方法和驗證微信服務器消息真實性類似。流程如下:
1. 將token、OpenID、timestamp三個參數進行字典序排序。 2. 將三個參數字符串拼接成一個字符串進行sha1加密,得到鏈接的signature參數。
- 用戶打開某個綁定鏈接時,你首先驗證鏈接的有效性,即按上述5.1和5.2中描述的同樣的步驟得到signature與參數中的sinature對比,如果相同,則再檢查鏈接是否超時,兩步驗證均通過,你就可以將用戶的微信OpenID設置到用戶的session中,然后你就可以渲染驗證頁面,讓用戶輸入其系統用戶名和密碼以提交給你服務器進行驗證。
- 在用戶提交綁定驗證請求后,你只需要檢查session中有沒有你設置的OpenID,沒有自然無效,有的話就是要綁定的OpenID了,此時你可以把這個OpenID從session中刪除了。然后你如果驗證系統用戶名和密碼通過后,就把這個OpenID和系統用戶綁定起來,加入到第1步中說的綁定關系表中。
關於微信公眾號用戶賬號綁定就是這么多,其實很容易實現,我在這里把我的方法和大家分享一下,老鳥可以忽略,主要是希望對新手有一些幫助。歡迎探討,敬請輕拍。