最終的解決方案是:https://github.com/liuyunzhuge/php_weixin_proxy,詳細的介紹請往下閱讀。php
在作項目集成微信登陸以及微信支付的時候,都須要進行用戶受權。這個受權的流程能夠簡單描述爲:
1. 用戶從咱們的應用觸發須要受權的操做,好比點擊微信登陸;
2. 應用收到這種用戶請求後,將用戶重定向到微信提供的一個受權頁面:
或
3. 用戶經過微信掃碼(PC端受權,上邊左圖)或者點擊確認按鈕(移動端受權,上邊右圖)告知微信,受權應用訪問本身的微信帳號信息;
4. 微信收到用戶的受權許可後,生成受權碼,並把它做爲參數回調至應用的某個頁面;
5. 應用的回調頁面在接收到微信的回調請求後,拿到其中的受權碼,並經過微信官方提供的access token api接口獲取access token;
6. 最後經過access token以及微信官方提供的另外一個userinfo api接口就能獲取到用戶的微信帳號信息。html
爲了實現這個過程,首先要爲應用申請一個微信公衆號,並將應用最終部署的域名設置到微信公衆號設置裏面的受權回調頁面域名這個選項裏面。微信官方對這個選項的說明以下:git
關於網頁受權回調域名的說明github
一、在微信公衆號請求用戶網頁受權以前,開發者須要先到公衆平臺官網中的「開發 - 接口權限 - 網頁服務 - 網頁賬號 - 網頁受權獲取用戶基本信息」的配置選項中,修改受權回調域名。請注意,這裏填寫的是域名(是一個字符串),而不是URL,所以請勿加 http:// 等協議頭; api
二、受權回調域名配置規範爲全域名,好比須要網頁受權的域名爲:www.qq.com,配置之後此域名下面的頁面http://www.qq.com/music.html 、 http://www.qq.com/login.html 均可以進行OAuth2.0鑑權。但http://pay.qq.com 、 http://music.qq.com 、 http://qq.com沒法進行OAuth2.0鑑權 微信
三、若是公衆號登陸受權給了第三方開發者來進行管理,則沒必要作任何設置,由第三方代替公衆號實現網頁受權便可架構
因而可知,這個規則極其嚴格。若是說咱們的應用最終部署的時候只有一個域名,那麼這種規則不會有什麼問題;可是考慮到未來應用的複雜性,咱們可能在應用設計之初就會對應用作拆分,而後不一樣的業務採用不一樣的二級域名來部署。好比一個帶有交易的應用,你可能會把登陸註冊,交易管理和常規業務都獨立出來,而後採用如下的方式來部署它們:
www.your.com 部署常規業務;
trade.your.com 部署交易管理的業務;
passport.your.com 部署登陸註冊的業務;
在這種模式下,若是集成微信登陸和微信支付,前面說的受權回調頁面域名的規則就會給應用帶來問題。在這裏:至少能夠確認trade.your.com和passport.your.com都須要前面的介紹的用戶微信受權,可是它們是兩個不一樣的子域名,並且咱們只有一個公衆號;根據受權回調頁面域名的原則,它只能用一個域名,而且只有回調地址的域名與該設置徹底相同,才能成功發起微信受權,不然就會提示rediret_uri參數錯誤或者引起沒法回調的問題。app
那麼這種狀況該如何處理?測試
當下的解決方案是引入一個新的很是簡單的應用來做爲微信受權的代理服務,能夠這麼作:
1. 把公衆號的網頁受權接口域名設置成另一個子域名,如proxy.your.com;
2. 而後把php_weixin_proxy裏面的index.php部署到proxy.your.com微信支付
php_weixin_proxy下的index.php是一個很簡單的php文件,你能夠直接查看源碼瞭解它的實現方式。由於當前項目的環境,我採用php來完成這個代理服務實現,實際上,你徹底能夠用任意平臺語言來完成相似的功能。
當其它業務須要發起微信受權時,將受權請求先發到proxy.your.com,而後proxy.your.com會把這個請求轉發到微信;
當用戶贊成受權後,proxy.your.com會收到微信的受權回調,並把回調結果(code、state參數)原封不動地再返回給最開始發起受權的業務。
惟一的區別在於,在不使用proxy.your.com的時候,你從應用發起微信受權的連接應該是這樣的:
https://open.weixin.qq.com/connect/qrconnect?appid=xxxxx&redirect_uri=http%3A%2F%2Fpassport.your.com%2F&response_type=code&scope=snsapi_login&state=584bc87e11ff37492#wechat_redirect
用了proxy.your.com以後,這個受權連接就應該是這樣的:
http://proxy.your.com/?appid=xxxxx&redirect_uri=http%3A%2F%2Fpassport.your.com%2Flogin%2Fnotify&response_type=code&scope=snsapi_base&state=584bc87e11ff37492&device=pc
後面這個連接跟上面的比:
1. 後面的連接中的host變成了proxy.your.com,也就是代理的受權回調域名;
2. 後面的多了一個device參數,這個是必要的。由於微信pc端跟移動端的受權地址是不同的,然後面的連接是發送個proxy.your.com的,因此須要多加個參數告訴它在轉發給受權申請給微信的時候,是用PC端仍是移動端的受權地址。
總體方案思路:
小結:
這個方案我測試過,是行的通的。雖說引入了代理服務,增長了一次重定向操做,不過因爲這個受權請求並非全部請求都須要,因此實際上也不會對用戶體驗產生多大的影響,可是從架構上來講,它的好處很明顯,可以配合着應用的拆分邏輯,集成同一個公衆號的登陸及支付功能,沒必要爲每一個子應用都單獨申請一個公衆號來開發了(這種方式從業務上來講也不合理,一個公司哪須要運營那麼多公衆號)。