H5及web頁(yè)面微信授權(quán)登錄流程

PC端微信掃碼登錄流程:

為什么要微信登錄:

如果用戶在微信客戶端中訪問(wèn)第三方網(wǎng)頁(yè),公眾號(hào)可以通過(guò)微信網(wǎng)頁(yè)授權(quán)機(jī)制,來(lái)獲取用戶基本信息,進(jìn)而實(shí)現(xiàn)業(yè)務(wù)邏輯。微信擁有龐大且穩(wěn)定活躍的用戶基數(shù),直接將我們的app接入到微信的生態(tài)可以免去復(fù)雜的新用戶注冊(cè)流程,使用戶體驗(yàn)更良好。

微信登錄的幾種情況:
  • PC端:

    • PC端微信瀏覽器 -> 直接調(diào)用微信授權(quán)(不掃碼,使用微信服務(wù)號(hào)的appid和appsecret)

    • PC端其他瀏覽器 -> 跳轉(zhuǎn)微信的掃碼登錄頁(yè)面(需要掃碼,使用微信開(kāi)放平臺(tái)注冊(cè)的PC應(yīng)用appid和appsecret)

  • 移動(dòng)端:

    • 微信客戶端打開(kāi) -> 直接調(diào)用微信授權(quán)(不掃碼,使用微信服務(wù)號(hào)的appid和appsecret)

    • 其他手機(jī)瀏覽器打開(kāi) -> 跳轉(zhuǎn)微信的掃碼登錄頁(yè)面(需要掃碼,使用微信開(kāi)放平臺(tái)注冊(cè)的PC應(yīng)用appid和appsecret)

區(qū)分是否是PC環(huán)境的方法:

判斷是PC環(huán)境還是移動(dòng)環(huán)境是為了相應(yīng)切換應(yīng)用的布局,目前采用css媒體查詢來(lái)做判斷:

/* 屏幕寬度小于等于1070像素時(shí)識(shí)別為移動(dòng)端(1070像素是使推薦頁(yè)常用情報(bào)站欄不現(xiàn)實(shí)滾動(dòng)條的最小寬度) */
@media screen and (max-width: 1070px) {
    /* 移動(dòng)端布局css樣式 */
}
/* 屏幕寬度大于1071像素識(shí)別為PC端 */
@media screen and (min-width: 1071px) {
    /* PC端布局樣式 */
}

這里目前的設(shè)計(jì)是將判斷UI樣式和判斷登錄邏輯區(qū)分開(kāi)的,兩個(gè)功能分別獨(dú)立判斷

區(qū)分微信登錄的幾種情況的方法:
  • 前端在登錄時(shí)獲取用戶設(shè)備信息(userAgent)
let UA = navigator.userAgent.toLocaleLowerCase()  
// UA的格式可能因設(shè)備不同而采用不同的大小寫(xiě)格式這里我們先統(tǒng)一為小寫(xiě)方便下一步判斷
UA.indexOf("micromessenger") != -1
// 通過(guò)indexOf方法來(lái)判斷字符串里是否有要查詢的字段

前端操作

1 獲取code(此步驟由前端完成)
  • 首先要在微信開(kāi)放平臺(tái)里申請(qǐng)創(chuàng)建一個(gè)web應(yīng)用,填寫(xiě)完基本信息之后提交審核,最長(zhǎng)7個(gè)工作日,一般兩天就能下來(lái)。審核通過(guò)以后可以得到web應(yīng)用的AppID和AppSecret,稍后請(qǐng)求微信登錄的二維碼。

  • 在得到web應(yīng)用的AppID以后前端需要配置請(qǐng)求登錄二維碼的url:

// 前端使用appid和回調(diào)域名來(lái)獲取微信登陸二維碼

window.location.replace(
    "https://open.weixin.qq.com/connect/qrconnect?" +
    "appid=" + APP_id + "&" +
    "redirect_uri=" + encodeURIComponent('http://wx.digitwonder.com') + "&" +
    "scope=snsapi_login#wechat_redirect" )

這個(gè)配置中AppID字段是向后臺(tái)傳微信開(kāi)放平臺(tái)的web應(yīng)用AppID,回調(diào)地址也是在開(kāi)放平臺(tái)注冊(cè)時(shí)留的地址,而且這個(gè)回調(diào)地址的uri需要經(jīng)過(guò)encode編碼加密以后拼接到請(qǐng)求的。'scope'字段表示請(qǐng)求的作用域,微信掃碼登錄時(shí)scope字段固定寫(xiě)'snsapi_login'。將這個(gè)地址拼接好以后就可以將路由定向到微信的二維碼頁(yè)面了。

參數(shù)說(shuō)明
參數(shù) 是否必須 說(shuō)明
appid 應(yīng)用唯一標(biāo)識(shí)(前面認(rèn)證網(wǎng)頁(yè)應(yīng)用中獲得)
redirect_uri 重定向地址,需要進(jìn)行UrlEncode(前面認(rèn)證網(wǎng)頁(yè)應(yīng)用中獲得)
response_type 填code
scope 應(yīng)用授權(quán)作用域,擁有多個(gè)作用域用逗號(hào)(,)分隔,網(wǎng)頁(yè)應(yīng)用目前僅填寫(xiě)snsapi_login即可
state 用于保持請(qǐng)求和回調(diào)的狀態(tài),授權(quán)請(qǐng)求后原樣帶回給第三方。該參數(shù)可用于防止csrf攻擊(跨站請(qǐng)求偽造攻擊),建議第三方帶上該參數(shù),可設(shè)置為簡(jiǎn)單的隨機(jī)數(shù)加session進(jìn)行校驗(yàn)
  • 在頁(yè)面定位到微信二維碼頁(yè)面以后掃碼確認(rèn),頁(yè)面會(huì)被定向到之前配置的回調(diào)頁(yè)面地址并且將請(qǐng)求來(lái)的code拼接到url上一并返回,我們?cè)谖⑿糯_認(rèn)登陸以后回到url拼接有code的頁(yè)面獲取到code之后向后臺(tái)發(fā)送登陸請(qǐng)求。
// 聲明變量flag用來(lái)存儲(chǔ)微信回調(diào)頁(yè)面的code信息
let flag = flag.split("&")[0];
// 重定向該頁(yè)面的路由(清除url中的code) - 避免發(fā)送code請(qǐng)求
this.$router.replace({
  path: "/login",
  query: {
    redirect: this.$route.query.redirect
  }
});

this.request({
        url: "/biz/login/wx",  // 后臺(tái)接收code的接口
        method: "POST",  // 使用HTTP的POST方法傳回code
        data: {
          code: flag  // 將頁(yè)面存儲(chǔ)code的flag變量以code字段傳給后臺(tái)
          // 此處區(qū)分登錄方式的字段待定
        }
      }).then(res => {
        // 前端本地獲取用戶信息后的方法
      })

后端操作

接口結(jié)構(gòu)

接口: (post)/biz/login/wx
參數(shù): browser(取值為 wx,other)
返回?cái)?shù)據(jù)(json):

// 登錄成功時(shí)返回
{
    "code": 1,
    "msg": "SUCCESS",
    "data": {
        "nick": "用戶昵稱",
        "role_id": 2,
        "mobile": "手機(jī)號(hào)",
        "avatar": "用戶頭像",
        "birthday": 1578909982972,
        "gender": 2,
        "location": "地區(qū)",
        "summary": "用戶簡(jiǎn)介",
        "eval": true,
        "status": "Complete",
        "last_login": 1578909982972,
        "id": "id",
        "create_time": 1571755690000,
        "update_time": 1578885503000
    }
}

// 登錄失敗時(shí)返回
{
    "code": 0,
    "msg": "FAILURE"
}
1 獲取access_token

收到登錄請(qǐng)求后首先通過(guò)code向微信服務(wù)器換取access_token。
根據(jù)不同的瀏覽器類型使用相應(yīng)的appid和secret

// 請(qǐng)求url(Get)
https://api.weixin.qq.com/sns/oauth2/access_token?appid=APPID&secret=SECRET&code=CODE&grant_type=authorization_code
參數(shù)說(shuō)明
參數(shù) 是否必須 說(shuō)明
appid 應(yīng)用唯一標(biāo)識(shí)
secret 應(yīng)用密鑰AppSecret
code 填寫(xiě)第一步獲取的code參數(shù)
grant_type 填authorization_code

微信瀏覽器登錄時(shí)使用公眾號(hào)appid和secret, 其他瀏覽器登錄使用網(wǎng)站應(yīng)用appid和secret

返回?cái)?shù)據(jù)說(shuō)明
名稱 類型 說(shuō)明
access_token String access_token
expires_in int access_token有效時(shí)間
refresh_token String refresh_token
openid String open_id
scope String 授權(quán)作用域

當(dāng)獲取數(shù)據(jù)出錯(cuò)時(shí),返回結(jié)果中包含"errCode"字段, 登錄失敗

2 拉取用戶信息

通過(guò)第一步中獲取到的access_token和openid拉取user_info

// 請(qǐng)求url(Get)
https://api.weixin.qq.com/sns/userinfo?access_token=ACCESS_TOKEN&openid=OPENID&lang=zh_CN
參數(shù)說(shuō)明
參數(shù) 是否必須 說(shuō)明
access_token 上一步中獲取到的access_token
openid 微信用戶唯一標(biāo)識(shí),上一步中獲取到的openid
返回?cái)?shù)據(jù)說(shuō)明
名稱 類型 說(shuō)明
openid String open_id
unionid String union_id
nickname String 用戶昵稱
sex int 性別
province String
city String 城市
country String 國(guó)家
headimgurl String 用戶頭像
privilege Array 用戶權(quán)限

當(dāng)獲取數(shù)據(jù)出錯(cuò)時(shí),返回結(jié)果中包含"errCode"字段, 登錄失敗

3 生成或獲取本地用戶
  • 通過(guò)union_id獲取第三方平臺(tái)賬號(hào)
  • 第三方平臺(tái)賬號(hào)存在時(shí)通過(guò)uid獲取用戶數(shù)據(jù),否則繼續(xù)
  • 使用微信登錄的賬戶需要將其用戶數(shù)據(jù)轉(zhuǎn)換成本地用戶并存儲(chǔ)
  • 添加用戶緩存
  • 創(chuàng)建或更新用戶Auth數(shù)據(jù)
  • 更新ES(UserIndex)
  • 創(chuàng)建用戶媒體
4 返回用戶數(shù)據(jù)

將用戶數(shù)據(jù)返回到前臺(tái)

時(shí)序圖

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

推薦閱讀更多精彩內(nèi)容