對於微信二維碼相關官方文檔的一些註解(微信登陸和綁定微信、關注公衆號)

轉載自:https://www.jianshu.com/p/d533c69be034html

  • 因爲微信官方文檔對此的描述雖然還能夠,可是仍是有一些讓人疑惑的地方,因此筆者作了一些註解,但願對你們有所幫助

爲何不直接寫一遍呢?由於懶~~~nginx

  • 爲方便你們後續找資料,文中出現的連接彙總放到了文章末尾
  • 因爲時間和水平有限,會有錯漏。若是讀者發現問題,請及時聯繫博主。

微信登陸和綁定微信

官方文檔請看 :網站應用微信登陸開發指南git

下面是搬運紅色字體爲註釋或補充)。固然,後面會有總結的,不是所有搬運,放心。github


準備工做

網站應用微信登陸是基於OAuth2.0協議標準構建的微信OAuth2.0受權登陸系統。
在進行微信OAuth2.在進行微信OAuth2.0受權登陸接入以前,在微信開放平臺註冊開發者賬號,並擁有一個已審覈經過的網站應用,並得到相應的AppID和AppSecret,申請微信登陸且經過審覈後,可開始接入流程。web

受權流程說明

微信OAuth2.0受權登陸讓微信用戶使用微信身份安全登陸第三方應用或網站,在微信用戶受權登陸已接入微信OAuth2.0的第三方應用後,第三方能夠獲取到用戶的接口調用憑證(access_token),經過access_token能夠進行微信開放平臺受權關係接口調用,從而可實現獲取微信用戶基本開放信息和幫助用戶實現基礎開放功能等。
微信OAuth2.0受權登陸目前支持authorization_code模式,適用於擁有server端的應用受權。該模式總體流程爲:數據庫

  1. 第三方發起微信受權登陸請求,微信用戶容許受權第三方應用後,微信會拉起應用或重定向到第三方網站,而且帶上受權臨時票據code參數;
  2. 經過code參數加上AppID和AppSecret等,經過API換取access_token;
  3. 經過access_token進行接口調用,獲取用戶基本數據資源或幫助用戶實現基本操做。

獲取access_token時序圖

第一步:請求CODEjson

第三方使用網站應用受權登陸前請注意已獲取相應網頁受權做用域(scope=snsapi_login),則能夠經過在PC端打開如下連接:
https://open.weixin.qq.com/co...
若提示「該連接沒法訪問」,請檢查參數是否填寫錯誤,如redirect_uri的域名與審覈時填寫的受權域名不一致或scope不爲snsapi_login。後端

參數說明api

參數 是否必須 說明
appid 應用惟一標識
redirect_uri 請使用urlEncode對連接進行處理,redirect_uri是微信服務器在用戶掃碼操做以後,經過調用這個url把事件發送給咱們的後端,也就是說,這個redirect_uri,是一個api,但這個api是能夠在公網上curl鏈接的。咱們要在開放平臺添加網站應用的時候設置一個回調域名,這個回調域名,就是redirect_uri的前綴,加上回調api的名字,就是完整的redirect_uri。(看不懂沒關係,後面有舉例)
response_type 填code
scope 應用受權做用域,擁有多個做用域用逗號(,)分隔,網頁應用目前僅填寫snsapi_login即
state 用於保持請求和回調的狀態,受權請求後原樣帶回給第三方。該參數可用於防止csrf攻擊(跨站請求僞造攻擊),建議第三方帶上該參數,可設置爲簡單的隨機數加session進行校驗

返回說明瀏覽器

用戶容許受權後,將會重定向到redirect_uri的網址上,而且帶上code和state參數

redirect_uri?code=CODE&state=STATE

若用戶禁止受權,則重定向後不會帶上code參數,僅會帶上state參數

redirect_uri?state=STATE

爲了知足網站更定製化的需求,咱們還提供了第二種獲取code的方式,支持網站將微信登陸二維碼內嵌到本身頁面中,用戶使用微信掃碼受權後經過JS將code返回給網站。(咱們主要講的就是這一種
JS微信登陸主要用途:網站但願用戶在網站內就能完成登陸,無需跳轉到微信域下登陸後再返回,提高微信登陸的流暢性與成功率。 網站內嵌二維碼微信登陸JS實現辦法:

步驟1:在頁面中先引入以下JS文件(支持https):

http://res.wx.qq.com/connect/zh_CN/htmledition/js/wxLogin.js

步驟2:在須要使用微信登陸的地方實例如下JS對象:

var obj = new WxLogin({ self_redirect:true, id:"login_container",  appid: "",  scope: "",  redirect_uri: "",  state: "", style: "", href: "" });

參數說明

參數 是否必須 說明
self_redirect true:手機點擊確認登陸後能夠在 iframe 內跳轉到 redirect_uri,false:手機點擊確認登陸後能夠在 top window 跳轉到 redirect_uri。默認爲 false。
id 第三方頁面顯示二維碼的容器id
appid 應用惟一標識,在微信開放平臺提交應用審覈經過後得到
scope 應用受權做用域,擁有多個做用域用逗號(,)分隔,網頁應用目前僅填寫snsapi_login便可
redirect_uri 重定向地址,須要進行UrlEncode
state 用於保持請求和回調的狀態,受權請求後原樣帶回給第三方。該參數可用於防止csrf攻擊(跨站請求僞造攻擊),建議第三方帶上該參數,可設置爲簡單的隨機數加session進行校驗
style 提供"black"、"white"可選,默認爲黑色文字描述。詳見文檔底部FAQ
href 自定義樣式連接,第三方可根據實際需求覆蓋默認樣式。詳見文檔底部FAQ

第二步:經過code獲取access_token

經過code獲取access_token

https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code

參數說明

參數 是否必須 說明
appid 應用惟一標識,在微信開放平臺提交應用審覈經過後得到
secret 應用密鑰AppSecret,在微信開放平臺提交應用審覈經過後得到
code 填寫第一步獲取的code參數
grant_type 填authorization_code

返回說明

正確的返回:

{ "access_token":"ACCESS_TOKEN", "expires_in":7200, "refresh_token":"REFRESH_TOKEN","openid":"OPENID", "scope":"SCOPE","unionid": "o6_bmasdasdsad6_2sgVt7hMZOPfL"}

參數說明

參數 說明
access_token 接口調用憑證
expires_in access_token接口調用憑證超時時間,單位(秒)
refresh_token 用戶刷新access_token
openid 受權用戶惟一標識
scope 用戶受權的做用域,使用逗號(,)分隔
unionid 當且僅當該網站應用已得到該用戶的userinfo受權時,纔會出現該字段。

錯誤返回樣例:

{"errcode":40029,"errmsg":"invalid code"}

注意:

一、Appsecret 是應用接口使用密鑰,泄漏後將可能致使應用數據泄漏、應用的用戶數據泄漏等高風險後果;存儲在客戶端,極有可能被惡意竊取(如反編譯獲取Appsecret);二、access_token 爲用戶受權第三方應用發起接口調用的憑證(至關於用戶登陸態),存儲在客戶端,可能出現惡意獲取access_token 後致使的用戶數據泄漏、用戶微信相關接口功能被惡意發起等行爲;三、refresh_token 爲用戶受權第三方應用的長效憑證,僅用於刷新access_token,但泄漏後至關於access_token 泄漏,風險同上。建議將secret、用戶數據(如access_token)放在App雲端服務器,由雲端中轉接口調用請求。

第三步:經過access_token調用接口

獲取access_token後,進行接口調用,有如下前提:

1. access_token有效且未超時;2. 微信用戶已受權給第三方應用賬號相應接口做用域(scope)。

對於接口做用域(scope),能調用的接口有如下:

受權做用域(scope) 接口 接口說明
snsapi_base /sns/oauth2/access_token 經過code換取access_token、refresh_token和已受權scope
snsapi_base /sns/oauth2/refresh_token 刷新或續期access_token使用
snsapi_base /sns/auth 檢查access_token有效性
snsapi_userinfo /sns/userinfo 獲取用戶我的信息() (<font color=red>敲黑板</font>)

其中snsapi_base屬於基礎接口,若應用已擁有其它scope權限,則默認擁有snsapi_base的權限。使用snsapi_base可讓移動端網頁受權繞過跳轉受權登陸頁請求用戶受權的動做,直接跳轉第三方網頁帶上受權臨時票據(code),但會使得用戶已受權做用域(scope)僅爲snsapi_base,從而致使沒法獲取到須要用戶受權才容許得到的數據和基礎功能。
接口調用方法可查閱微信受權關係接口調用指南

F.A.Q

  1. 什麼是受權臨時票據(code)?
    答:第三方經過code進行獲取access_token的時候須要用到,code的超時時間爲10分鐘,一個code只能成功換取一次access_token即失效。code的臨時性和一次保障了微信受權登陸的安全性。第三方可經過使用https和state參數,進一步增強自身受權登陸的安全性。
  2. 什麼是受權做用域(scope)?
    答:受權做用域(scope)表明用戶受權給第三方的接口權限,第三方應用須要向微信開放平臺申請使用相應scope的權限後,使用文檔所述方式讓用戶進行受權,通過用戶受權,獲取到相應access_token後方可對接口進行調用。
    • *

總結

  1. 用微信給的一個組件wxlogin生成二維碼(其實生成二維碼就是這麼簡單)

    var obj = new WxLogin({ self_redirect:true, id:"login_container",  appid: "",  scope: "",  redirect_uri: "",  state: "", style: "", href: "" });
    • redirect_uri:設定用戶掃碼操做以後,微信服務器調用的api地址(這個後端api是處理用戶掃碼後的事件的,由於咱們是不知道用戶有沒有掃碼的,因此要經過微信的服務器調用咱們的api,來讓咱們自定義操做來處理掃碼事件)。redirect_uri地址由咱們的服務器域名(不能是公網IP!!) + 後端api名組成(至於爲何,看後面)。咱們要在微信開放平臺的網站應用中設置一個回調域名,就是咱們的服務器域名,以便微信服務器能調用咱們的api(但我不懂的是,萬一有其餘人調了咱們的api咋辦,hhhh,這個我後面去查一下吧)。

      • 設置方法:微信開放平臺->管理中心->網站應用->在應用名右邊點擊查看->開發信息->修改(受權回調域)
    • state:會放在微信服務器對後端api的調用時post的參數裏,能夠用於場景判斷。就是咱們是拿這個二維碼來實現登陸的,那就設定state爲"auth",咱們的後端api就能夠根據這個來對用戶進行響應。(固然,其實上面的官方文檔不是讓咱們這麼用的,嘻嘻嘻)
    1. 而後就是用戶掃描二維碼以後,咱們的網站如何接收用戶的操做,並進行響應。

      • 是利用咱們在微信開放平臺設置的回調地址,來讓微信服務器把用戶的操做經過回調咱們在redirect_uri指定的api來傳遞給咱們的網站後端。如今再看下面這張圖應該就會有必定的理解了。

        獲取access_token時序圖

    2. 後端接收了微信服務器發送的信息以後,對用戶的操做進行響應

      • 調用下面的鏈接。經過上面拿到的code換取access_token

        https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code
      • 經過access_token來獲取用戶的信息,進而檢驗用戶是否在數據庫內,或這把用戶的unionid加進相應的數據庫表中。

    可能出現的問題及解決

    1. 實現展現二維碼時

      這裏若是是在本地測試運行,應該會出現一個問題,就是redirect_uri參數錯誤。這個問題出現的緣由有

      • 沒有進行UrlEncode
      • 地址不是咱們在微信開放平臺設置的那個

        第一個好解決,encode一下就好。可是第二個問題的話,因爲填寫的地址是要公網能夠訪問的,而咱們在本地調試的時候,是內網,公網沒法訪問,這樣的話,微信服務器就沒法回調咱們的api。那這個問題怎麼解決呢?

        噹噹噹,frp,內網穿透利器。

    frp

    1. 簡介

      ​ frp是快速反向代理,可幫助您將NAT或防火牆後面的本地服務器公開到Internet。到目前爲止,它支持tcp&udp以及http和https協議,能夠在其中將請求經過域名轉發到內部服務。(github上的)

    2. 說明

      ​ 說的大白話一點,就是咱們本地的運行的服務器,好比網站,是沒法經過公網直接訪問的(就是你的電腦上運行的了一個網站,它的地址是xxx.xxx.xxx.xxx:8080,可是你讓你舍友用他的電腦訪問這個地址,是沒法訪問的),而你要讓他訪問你的網站,就要利用有公網域名的服務器。有公網域名的服務器是能夠訪問的,再讓服務器轉發請求到你本地的機子,這樣就實現了內網穿透。

      ​ 這裏你們可能就蒙了,既然我舍友訪問不了,那爲何有公網ip的服務器就能訪問個人本地了呢?這不是耍流氓了嗎。

      ​ 那我下面把frp的運做過程給你們看一下,你們應該就明白了

    3. frp運做流程(以http爲例):

      1. 首先,根據咱們的操做系統和架構,從Release頁面下載最新frp程序。

        • 一份放到服務器,一份放本地
      2. 服務器運行frp_server

        1. 解壓後進入frp程序目錄
        2. 修改配置文件frps.ini以下
        # frps.ini 
        [common] 
        bind_port = 7000       # 服務器上frp運行的端口
        vhost_http_port = 8080 # 服務器上接收http請求(eg. 瀏覽器訪問)的端口
    3. 而後啓動frps(在命令行敲入如下命令)
    
      ```
      ./frps -c ./frps.ini
      ```
    1. 本地運行frp_client

      1. 解壓後進入frp程序目錄
      2. 修改配置文件frpc.ini以下

        # frpc.ini 
        [common] 
        server_addr = xxxx       # 服務器ip
        server_port = 7000         # 服務器上frp運行的端口
        
        [web] 
         type = http
         local_port = 80         # 本地服務運行的端口
         custom_domains = www.yourdomain.com
      3. 而後啓動frpc(在命令行敲入如下命令)

        ./frpc -c ./frpc.ini
    2. 本地的frp client經過server_addr鏈接服務器上的frp server ,注意啦,如今,本地已經與服務器創建聯繫
    3. 如今,使用url訪問你的本地Web服務http://www.yourdomain.com:8080,此時,瀏覽器會先訪問服務器的8080端口,而服務器接收到請求以後,把請求轉發給本地的80端口。(反向代理)
    4. 本地響應請求,把數據發給服務器,服務器再把數據發給用戶(eg. 你的舍友)

    好,如今已經能讓公網訪問咱們的本地的機子了。下一步,寫回調函數。

    1. 回調函數(這是咱們的一個示例)
    const wxLogin = async (req, res, next) => {
            const code = lo.get(req, 'query.code') 
            const state = lo.get(req, 'query.state')
            const userId = lo.get(req, 'rSession.userId') 
            try {
                const result = await web_codeToAccessToken(code)  //用code拿access_token
                if (state == 'bind') {
                    if (result.access_token && result.openid && result.unionid) {
                        //這裏寫綁定用戶微信相關操做,如寫入數據庫等
                        const userInfo = await web_accessTokenToUserInfo(result.access_token, result.openid) //用code拿access_token
                    } else {
                        // 因爲某些緣由綁定失敗,進行處理
                        
                    }
                }
        
                if (state == 'auth') {
                    if (result.unionid) {
                        //這裏寫用戶微信登陸相關操做
    
                    } else {
                        // 因爲某些緣由受權失敗,進行處理
                       
                    }
                }
        
        
            } catch (error) {
                console.error(error);
            }
        }
    // 網頁登陸,用access_token + openid 拿用戶信息
    const web_accessTokenToUserInfo = async function (accessToken, openid) {
        const result = await fetch(`https://api.weixin.qq.com/sns/userinfo?access_token=${accessToken}&openid=${openid}`)
        const data = await result.json()
        return data
    }
    
    // 網頁登陸,用 code 拿用戶的 access_token (包括openid 和 unionid)
    const web_codeToAccessToken = async function (code) {
        const result = await fetch(`https://api.weixin.qq.com/sns/oauth2/access_token?appid=${yourAppid}&secret=${yoursecret}&code=${code}&grant_type=authorization_code`)
        const data = await result.json()
        return data
    }
    //這裏注意appid和secret是你本身的appid和secret

    關注公衆號

    生成帶參數的二維碼

    下面是搬運紅色字體爲註釋或補充


    爲了知足用戶渠道推廣分析和用戶賬號綁定等場景的須要,公衆平臺提供了生成帶參數二維碼的接口。使用該接口能夠得到多個帶不一樣場景值的二維碼,用戶掃描後,公衆號能夠接收到事件推送。

    目前有2種類型的二維碼:

    一、臨時二維碼,是有過時時間的,最長能夠設置爲在二維碼生成後的30天(即2592000秒)後過時,但可以生成較多數量。臨時二維碼主要用於賬號綁定等不要求二維碼永久保存的業務場景 二、永久二維碼,是無過時時間的,但數量較少(目前爲最多10萬個)。永久二維碼主要用於適用於賬號綁定、用戶來源統計等場景。

    用戶掃描帶場景值二維碼時,可能推送如下兩種事件:

    若是用戶還未關注公衆號,則用戶能夠關注公衆號,關注後微信會將帶場景值關注事件推送給開發者。

    若是用戶已經關注公衆號,在用戶掃描後會自動進入會話,微信也會將帶場景值掃描事件推送給開發者。

    獲取帶參數的二維碼的過程包括兩步,首先建立二維碼ticket,而後憑藉ticket到指定URL換取二維碼。

    建立二維碼ticket這裏的access_token是經過公衆號appid和appsecret拿到的,參見[獲取access_token](https://developers.weixin.qq.com/doc/offiaccount/Basic_Information/Get_access_token.html)這篇文章。因爲比較易懂就很少說了。但要注意的是:【經過公衆號appid和appsecret拿access_token,是要在[微信公衆平臺](https://mp.weixin.qq.com/)設置獲取access_token的ip白名單的。若是不在白名單,是沒法獲取的,切記,切記。設置方法:微信公衆平臺->開發->基本配置->ip白名單】

    每次建立二維碼ticket須要提供一個開發者自行設定的參數(scene_id),分別介紹臨時二維碼和永久二維碼的建立二維碼ticket過程。

    臨時二維碼請求說明

    http請求方式: POST
    URL: https://api.weixin.qq.com/cgi-bin/qrcode/create?access_token=TOKEN
    POST數據格式:json
    POST數據例子:{"expire_seconds": 604800, "action_name": "QR_SCENE", "action_info": {"scene": {"scene_id": 123}}}
    
    或者也可使用如下POST數據建立字符串形式的二維碼參數:
    {"expire_seconds": 604800, "action_name": "QR_STR_SCENE", "action_info": {"scene": {"scene_str": "test"}}}

    永久二維碼請求說明

    http請求方式: POST
    URL: https://api.weixin.qq.com/cgi-bin/qrcode/create?access_token=TOKEN
    POST數據格式:json
    POST數據例子:{"action_name": "QR_LIMIT_SCENE", "action_info": {"scene": {"scene_id": 123}}}
    
    或者也可使用如下POST數據建立字符串形式的二維碼參數:
    {"action_name": "QR_LIMIT_STR_SCENE", "action_info": {"scene": {"scene_str": "test"}}}

    參數說明

    參數 說明
    expire_seconds 該二維碼有效時間,以秒爲單位。 最大不超過2592000(即30天),此字段若是不填,則默認有效期爲30秒。
    action_name 二維碼類型,QR_SCENE爲臨時的整型參數值,QR_STR_SCENE爲臨時的字符串參數值,QR_LIMIT_SCENE爲永久的整型參數值,QR_LIMIT_STR_SCENE爲永久的字符串參數值
    action_info 二維碼詳細信息
    scene_id 場景值ID,臨時二維碼時爲32位非0整型,永久二維碼時最大值爲100000(目前參數只支持1--100000)
    scene_str 場景值ID(字符串形式的ID),字符串類型,長度限制爲1到64

    返回說明

    正確的Json返回結果:

    {"ticket":"gQH47joAAAAAAAAAASxodHRwOi8vd2VpeGluLnFxLmNvbS9xL2taZ2Z3TVRtNzJXV1Brb3ZhYmJJAAIEZ23sUwMEmm
    3sUw==","expire_seconds":60,"url":"http://weixin.qq.com/q/kZgfwMTm72WWPkovabbI"}
    參數 說明
    ticket 獲取的二維碼ticket,憑藉此ticket能夠在有效時間內換取二維碼。
    expire_seconds 該二維碼有效時間,以秒爲單位。 最大不超過2592000(即30天)。
    url 二維碼圖片解析後的地址,開發者可根據該地址自行生成須要的二維碼圖片

    經過ticket換取二維碼

    獲取二維碼ticket後,開發者可用ticket換取二維碼圖片。請注意,本接口無須登陸態便可調用。

    請求說明

    HTTP GET請求(請使用https協議)https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket=TICKET
    提醒:TICKET記得進行UrlEncode

    返回說明

    ticket正確狀況下,http 返回碼是200,是一張圖片,能夠直接展現或者下載。

    HTTP頭(示例)以下:
    Accept-Ranges:bytes
    Cache-control:max-age=604800
    Connection:keep-alive
    Content-Length:28026
    Content-Type:image/jpg
    Date:Wed, 16 Oct 2013 06:37:10 GMT
    Expires:Wed, 23 Oct 2013 14:37:10 +0800
    Server:nginx/1.4.1

    錯誤狀況下(如ticket非法)返回HTTP錯誤碼404。


    總結

    1.用戶掃碼以後關注公衆號,或者,用戶取消關注(這個是不用掃碼的),微信服務器都會推送信息給咱們的網站(其實就是調用咱們約定好的api)

    2.這裏咱們注意到,不像微信登陸和綁定那樣,在微信開放平臺設置接收信息的域名,而後還要設置redirect_uri。這裏的話,直接在微信公衆平臺設置接收信息推送的api地址就行了。

    • 設置方法:微信公衆平臺->開發->基本配置->服務器配置

    3.而後只要用戶關注了公衆號或取消關注,微信服務器都會調用咱們設置的api,推送信息給咱們的網站,而後咱們的網站後端處理事件。

    連接彙總

    相關文章
    相關標籤/搜索