1. 程式人生 > >微信公眾號開發之微信網頁授權獲取使用者個人資訊

微信公眾號開發之微信網頁授權獲取使用者個人資訊

說明:該篇部落格是博主一字一碼編寫的,實屬不易,請尊重原創,謝謝大家!

一丶概述

  • 微信網頁授權

如果使用者在微信客戶端中訪問第三方網頁,公眾號可以通過微信網頁授權機制,來獲取使用者基本資訊,進而實現業務邏輯。

現在,我們要實現一個微信內網頁,通過微信訪問網頁時,網頁會展示微信使用者的個人資訊。因為涉及到使用者的個人資訊,所以需要有使用者授權才可以。當用戶授權後,我們的網頁伺服器(開發者伺服器)會拿到使用者的“授權書”(code),我們用這個code向微信伺服器領取訪問令牌(accecc_token)和使用者的身份號碼(openid),然後憑藉access_token和openid向微信伺服器提取使用者的個人資訊。

  1. 第一步:使用者同意授權,獲取code
  2. 第二步:通過code換取網頁授權access_token
  3. 第三步:拉取使用者資訊(需scope為 snsapi_userinfo)

那麼,如何拿到使用者的授權code呢?

授權是由微信發起讓使用者進行確認,在這個過程中是微信在與使用者進行互動,所以使用者應該先訪問微信的內容,使用者確認後再由微信將使用者導向到我們的網頁連結地址,並攜帶上code引數。我們把這個過程叫做網頁回撥,類似於我們在程式編寫時用到的回撥函式,都是回撥的思想。

  • 關於網頁授權回撥域名的說明 

1、在微信公眾號請求使用者網頁授權之前,開發者需要先到公眾平臺官網中的“開發 - 介面許可權 - 網頁服務 - 網頁帳號 - 網頁授權獲取使用者基本資訊”的配置選項中,修改授權回撥域名。請注意,這裡填寫的是域名(是一個字串),而不是URL,因此請勿加 http:// 等協議頭;關於網頁授權回撥域名的說明

2、授權回撥域名配置規範為全域名,比如需要網頁授權的域名為: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鑑權

3、如果公眾號登入授權給了第三方開發者來進行管理,則不必做任何設定,由第三方代替公眾號實現網頁授權即可。

第一步:使用者同意授權,獲取code

在確保微信公眾賬號擁有授權作用域(scope引數)的許可權的前提下(服務號獲得高階介面後,預設擁有scope引數中的snsapi_base和snsapi_userinfo),引導關注者開啟如下頁面:

https://open.weixin.qq.com/connect/oauth2/authorize?appid=APPID&redirect_uri=REDIRECT_URI&response_type=code&scope=SCOPE&state=STATE#wechat_redirect

尤其注意:由於授權操作安全等級較高,所以在發起授權請求時,微信會對授權連結做正則強匹配校驗,如果連結的引數順序不對,授權頁面將無法正常訪問

參考連結(請在微信客戶端中開啟此連結體驗):
scope為snsapi_base
https://open.weixin.qq.com/connect/oauth2/authorize?appid=wx520c15f417810387&redirect_uri=https%3A%2F%2Fchong.qq.com%2Fphp%2Findex.php%3Fd%3D%26c%3DwxAdapter%26m%3DmobileDeal%26showwxpaytitle%3D1%26vb2ctag%3D4_2030_5_1194_60&response_type=code&scope=snsapi_base&state=123#wechat_redirect
scope為snsapi_userinfo
https://open.weixin.qq.com/connect/oauth2/authorize?appid=wxf0e81c3bee622d60&redirect_uri=http%3A%2F%2Fnba.bluewebgame.com%2Foauth_response.php&response_type=code&scope=snsapi_userinfo&state=STATE#wechat_redirec

尤其注意:跳轉回調redirect_uri,應當使用https連結來確保授權code的安全性。

引數說明

引數 是否必須 說明
appid 公眾號的唯一標識
redirect_uri 授權後重定向的回撥連結地址, 請使用 urlEncode 對連結進行處理
response_type 返回型別,請填寫code
scope 應用授權作用域,snsapi_base (不彈出授權頁面,直接跳轉,只能獲取使用者openid),snsapi_userinfo (彈出授權頁面,可通過openid拿到暱稱、性別、所在地。並且, 即使在未關注的情況下,只要使用者授權,也能獲取其資訊 )
state 重定向後會帶上state引數,開發者可以填寫a-zA-Z0-9的引數值,最多128位元組
#wechat_redirect 無論直接開啟還是做頁面302重定向時候,必須帶此引數

 下圖為scope等於snsapi_userinfo時的授權頁面:

使用者同意授權後

如果使用者同意授權,頁面將跳轉至 redirect_uri/?code=CODE&state=STATE。

code說明 : code作為換取access_token的票據,每次使用者授權帶上的code將不一樣,code只能使用一次,5分鐘未被使用自動過期。 

第二步:通過code換取網頁授權access_token

首先請注意,這裡通過code換取的是一個特殊的網頁授權access_token,與基礎支援中的access_token(該access_token用於呼叫其他介面)不同。公眾號可通過下述介面來獲取網頁授權access_token。如果網頁授權的作用域為snsapi_base,則本步驟中獲取到網頁授權access_token的同時,也獲取到了openid,snsapi_base式的網頁授權流程即到此為止。

尤其注意:由於公眾號的secret和獲取到的access_token安全級別都非常高,必須只儲存在伺服器,不允許傳給客戶端。後續重新整理access_token、通過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

返回說明

正確時返回的JSON資料包如下:

{ "access_token":"ACCESS_TOKEN",
"expires_in":7200,
"refresh_token":"REFRESH_TOKEN",
"openid":"OPENID",
"scope":"SCOPE" }
引數 描述
access_token 網頁授權介面呼叫憑證,注意:此access_token與基礎支援的access_token不同
expires_in access_token介面呼叫憑證超時時間,單位(秒)
refresh_token 使用者重新整理access_token
openid 使用者唯一標識,請注意,在未關注公眾號時,使用者訪問公眾號的網頁,也會產生一個使用者和公眾號唯一的OpenID
scope 使用者授權的作用域,使用逗號(,)分隔

 

錯誤時微信會返回JSON資料包如下(示例為Code無效錯誤):

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

 第三步:拉取使用者資訊(需scope為 snsapi_userinfo)

如果網頁授權作用域為snsapi_userinfo,則此時開發者可以通過access_token和openid拉取使用者資訊了。

請求方法

http:GET(請使用https協議) https://api.weixin.qq.com/sns/userinfo?access_token=ACCESS_TOKEN&openid=OPENID&lang=zh_CN

引數說明

引數 描述
access_token 網頁授權介面呼叫憑證,注意:此access_token與基礎支援的access_token不同
openid 使用者的唯一標識
lang 返回國家地區語言版本,zh_CN 簡體,zh_TW 繁體,en 英語

返回說明

正確時返回的JSON資料包如下:

{    "openid":" OPENID",
" nickname": NICKNAME,
"sex":"1",
"province":"PROVINCE"
"city":"CITY",
"country":"COUNTRY",
"headimgurl":    "http://thirdwx.qlogo.cn/mmopen/g3MonUZtNHkdmzicIlibx6iaFqAc56vxLSUfpb6n5WKSYVY0ChQKkiaJSgQ1dZuTOgvLLrhJbERQQ4eMsv84eavHiaiceqxibJxCfHe/46",
"privilege":[ "PRIVILEGE1" "PRIVILEGE2"     ],
"unionid": "o6_bmasdasdsad6_2sgVt7hMZOPfL"
}
引數 描述
openid 使用者的唯一標識
nickname 使用者暱稱
sex 使用者的性別,值為1時是男性,值為2時是女性,值為0時是未知
province 使用者個人資料填寫的省份
city 普通使用者個人資料填寫的城市
country 國家,如中國為CN
headimgurl 使用者頭像,最後一個數值代表正方形頭像大小(有0、46、64、96、132數值可選,0代表640*640正方形頭像),使用者沒有頭像時該項為空。若使用者更換頭像,原有頭像URL將失效。
privilege 使用者特權資訊,json 陣列,如微信沃卡使用者為(chinaunicom)
unionid 只有在使用者將公眾號繫結到微信開放平臺帳號後,才會出現該欄位。

錯誤時微信會返回JSON資料包如下(示例為openid無效):

{"errcode":40003,"errmsg":" invalid openid "}

 二丶程式碼實現

  • 思路分析
  • 首選在我們的flask程式中需要定義一個檢視函式路由規則為/wechat8007/index,定義微信伺服器重定向網址redirect_uri為伺服器域名+/wechat8007/index(例如http://www.xxxx.com/wechat8007/index),通過訪問微信提供的引導頁面,讓使用者同意授權,然後重定向到我們定義的網址,此時微信伺服器就會給我們的服務一個code,我們的伺服器再通過code向微信伺服器換取網頁授權access_token(存取令牌),如果網頁授權作用域為snsapi_userinfo,則此時可以通過access_token和openid拉取使用者資訊了。
  • step1 同意授權,這一塊不需要程式碼實現,只需要提供授權連結即可
  • step2 定義檢視函式,當用戶同意授權,頁面將跳轉至 redirect_uri/?code=CODE&state=STATE ,在flask程式中定義一個是檢視函式介面index,讓使用者同意授權後,去訪問的檢視
  • 上一篇部落格定義的wechat檢視,是由微信伺服器訪問,現在定義的index檢視為使用者訪問的
@app.route("/wechat8007/index")
def index():
    """讓使用者通過微信訪問的網頁頁面檢視"""
  • step3  剛開始還沒拉去使用者資料時,可直接返回一個模板
return render_template("index.html")
  • step4 從微信伺服器中獲取使用者的資料資料,將使用者的資料資料填充到index.html模板中
  • 1.獲取code引數
code = request.args.get("code")
  • 2.當code不存在時,返回字串
if not code:
    return u"缺失code引數"
url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=%s&secret=%s&code=%s&grant_type=authorization_code" %(WECHAT_APPID,WECHAT_APPSECRET,code)

response = urllib2.urlopen(url)

# 獲取響應體資料,微信返回的json資料
json_str = response.read()
resp_dict = json.loads(json_str)
  • 4.提取access_token,首先對獲取到的響應體資料進行判斷,如果不存在,直接返回提示字串,存在則通過get方式拿去字典中的access_token鍵的值以及使用者編號openid的值
if "errcode" in resp_dict:
    return u"獲取access_token失敗"

access_token = resp_dict.get("access_token")
open_id = resp_dict.get("openid")  # 使用者的編號
  • step5 向微信伺服器傳送http請求,獲取使用者的資料資料 
url = "https://api.weixin.qq.com/sns/userinfo?access_token=%s&openid=%s&lang=zh_CN" %(access_token,open_id)

response = urllib2.urlopen(url)

# 讀取微信傳回的json的響應體資料
user_json_str = response.read()
user_dict_data = json.loads(user_json_str)
  • step6 判斷微信返回的響應體資料中是否有errorcode欄位,如果存在則返回失敗資訊,不存在說明微信返回的json資料為正確資料,則將該資料傳給index.html模板,當用戶訪問 http://xxx/wechat8007/index地址時,會渲染出我們定義的index.html模板
if "errcode" in user_dict_data:
    return u"獲取使用者資訊失敗"
else:
    # 將使用者的資料資料填充到頁面中
    return render_template("index.html", user=user_dict_data)
  •  step7 當前目錄下建立templates模板目錄,在該目錄中建立index.html檔案 ,程式碼如下
<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>{{user["nickname"]}}的個人主頁</title>
</head>
<body>
    <img alt="頭像" src="{{user['headimgurl']}}" width="60">
    <table>
        <tr>
            <th>openid</th>
            <td>{{user["openid"]}}</td>
        </tr>
        <tr>
            <th>暱稱</th>
            <td>{{user["nickname"]}}</td>
        </tr>
        <tr>
            <th>性別</th>
            <td>
                {% if 1 == user["sex"] %}
                    男
                {% elif 2 == user["sex"] %}
                    女
                {% else %}
                    未知
                {% endif %}
            </td>
        </tr>
        <tr>
            <th>省份</th>
            <td>{{user["province"]}}</td>
        </tr>
        <tr>
            <th>城市</th>
            <td>{{user["city"]}}</td>
        </tr>
        <tr>
            <th>國家</th>
            <td>{{user["country"]}}</td>
        </tr>
    </table>
</body>
</html>

 三丶部署測試

  • step1 將程式碼推送到伺服器上

成功推送到伺服器上

  •  step2 在伺服器上進入虛擬環境,執行此程式

 

In [1]: import urllib

In [2]: urllib.quote("http://www.xxx.com/wechat8007/index")
Out[2]: 'http%3A//www.xxx.com/wechat8007/index'


 

  • 拼接好的使用者訪問的url地址為

  • step4 可以將該網址生成二維碼,使用微信掃一掃,也可以在介面公眾號直接傳送此連結地址
  •  使用谷歌瀏覽器的二維碼外掛,將網址生成對應的二維碼(這裡以百度首頁網址為例)

  • 直接在瀏覽器中輸入此地址會提示請在微信客戶端開啟連結

  •  step5 測試,在手機微信上開啟此連結,出現授權登入提示,點選允許即可獲取使用者個人資訊

點選允許後,進入如下介面

點選繼續訪問,則出現博主個人的微信資訊了,如下圖 

此時檢視伺服器上程式執行日誌 

四丶完整程式碼

# coding:utf-8
from flask import Flask, request, render_template
import json, urllib2


WECHAT_APPID = "yourappid"
WECHAT_APPSECRET = "yoursecret"

app = Flask(__name__)



@app.route("/wechat8007/index")
def index():

    code = request.args.get("code")

    if not code:
        return u"缺失code引數"

    url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=%s&secret=%s&code=%s&grant_type=authorization_code" % (WECHAT_APPID, WECHAT_APPSECRET, code)

    response = urllib2.urlopen(url)

    json_str = response.read()
    resp_dict = json.loads(json_str)

    if "errcode" in resp_dict:
        return u"獲取access_token失敗"

    access_token = resp_dict.get("access_token")
    open_id = resp_dict.get("openid")

    url = "https://api.weixin.qq.com/sns/userinfo?access_token=%s&openid=%s&lang=zh_CN" % (access_token, open_id)

    response = urllib2.urlopen(url)
    user_json_str = response.read()
    user_dict_data = json.loads(user_json_str)

    if "errcode" in user_dict_data:
        return u"獲取使用者資訊失敗"
    else:
        return render_template("index.html", user=user_dict_data)


if __name__ == '__main__':
    app.run(port=8007, debug=True)

總結:微信公眾號介面開發,根據官方提供的開發文件,進行開發,邏輯實現都很簡單,多想多思考多練習,你會越來越棒的!