1.小程序登錄
小程序可以通過微信官方提供的登錄能力方便地獲取微信提供的用戶身份標識,快速建立小程序內的用戶體系。
登錄流程時序
說明:
- 調用 wx.login() 獲取 臨時登錄憑證code ,並回傳到開發者服務器。
- 調用 code2Session 接口,換取 用戶唯一標識 OpenID 和 會話密鑰 session_key。
之后開發者服務器可以根據用戶標識來生成自定義登錄態,用於后續業務邏輯中前后端交互時識別用戶身份。
注意:
- 會話密鑰
session_key
是對用戶數據進行 加密簽名 的密鑰。為了應用自身的數據安全,開發者服務器不應該把會話密鑰下發到小程序,也不應該對外提供這個密鑰。 - 臨時登錄憑證 code 只能使用一次
兄弟們,是不是很簡單,一看就會?我知道你們的回答如下圖,但是不要慌,我們詳細講每一步
小程序端執行wx.login后在回調函數中就能拿到上圖的code,然后把這個code傳給我們后端程序,后端拿到這個這個code后,可以請求code2Session接口拿到用的openid和session_key,openid是用戶在微信中唯一標識,我們就可以把這個兩個值(val)存起來,然后返回一個鍵(key)給小程序端,下次小程序請求我們后端的時候,帶上這個key,我們就能找到這個val,就可以,這樣就把登入做好了。
1.1wx.login(Object object)
調用接口獲取登錄憑證(code)。通過憑證進而換取用戶登錄態信息,包括用戶的唯一標識(openid)及本次登錄的會話密鑰(session_key)等。用戶數據的加解密通訊需要依賴會話密鑰完成。更多使用方法詳見 小程序登錄。
參數
Object object
屬性 | 類型 | 默認值 | 必填 | 說明 | 最低版本 |
---|---|---|---|---|---|
timeout | number | 否 | 超時時間,單位ms | 1.9.90 | |
success | function | 否 | 接口調用成功的回調函數 | ||
fail | function | 否 | 接口調用失敗的回調函數 | ||
complete | function | 否 | 接口調用結束的回調函數(調用成功、失敗都會執行) |
object.success 回調函數
參數
Object res
屬性 | 類型 | 說明 |
---|---|---|
code | string | 用戶登錄憑證(有效期五分鍾)。開發者需要在開發者服務器后台調用 code2Session,使用 code 換取 openid 和 session_key 等信息 |
示例代碼
wx.login({
success(res) {
if (res.code) {
// 發起網絡請求
wx.request({
url: 'https://test.com/onLogin',
data: {
code: res.code
},
success: function (res) {
wx.setStorageSync('login_key', res.data.data.login_key);
}
})
} else {
console.log('登錄失敗!' + res.errMsg)
}
}
})
1.2code2Session
本接口應在服務器端調用,詳細說明參見服務端API。
登錄憑證校驗。通過 wx.login() 接口獲得臨時登錄憑證 code 后傳到開發者服務器調用此接口完成登錄流程。更多使用方法詳見 小程序登錄。
請求地址
GET https://api.weixin.qq.com/sns/jscode2sessionappid=APPID&secret=SECRET&js_code=JSCODE&grant_type=authorization_code
請求參數
屬性 | 類型 | 默認值 | 必填 | 說明 |
---|---|---|---|---|
appid | string | 是 | 小程序 appId | |
secret | string | 是 | 小程序 appSecret | |
js_code | string | 是 | 登錄時獲取的 code | |
grant_type | string | 是 | 授權類型,此處只需填寫 authorization_code |
返回值
Object
返回的 JSON 數據包
屬性 | 類型 | 說明 |
---|---|---|
openid | string | 用戶唯一標識 |
session_key | string | 會話密鑰 |
unionid | string | 用戶在開放平台的唯一標識符,在滿足 UnionID 下發條件的情況下會返回,詳見 UnionID 機制說明。 |
errcode | number | 錯誤碼 |
errmsg | string | 錯誤信息 |
errcode 的合法值
值 | 說明 |
---|---|
-1 | 系統繁忙,此時請開發者稍候再試 |
0 | 請求成功 |
40029 | code 無效 |
45011 | 頻率限制,每個用戶每分鍾100次 |
說完上面的登入后,我們是不是還沒有用到上面的session_key?這個就是在用戶授權的時候用的,用來解密用戶的數據,還要解密?是的你沒有聽錯,不要慌,下面給你解釋
2.微信授權獲取用戶信
后端獲取微信用戶信息流程
微信官方:忘了告訴你,session_key還會過期的,是的,沒錯就是這樣坑爹。
我的回復:我就是頭鐵,我不管session_key過期,會帶來什么樣的后果呢?
微信官方:對不起,你頭鐵沒有,你后端程序無法用戶授權的數據,就問你氣不氣?
我的回復:好的,你牛逼,我可以接收你session_key過期,但是你要告訴我怎么判斷他是過期的吧?怎么獲取新的session_key吧?
微信官方:還是要按照我的要求來吧?看你這么可憐,告訴你吧,用wx.checkSession判斷是否過期,如果過期就重寫登入吧!獲取新的code,后端在去請求code2Session獲取新的session_key
我的回復:好的,謝謝你sb
2.1wx.checkSession(Object object)
檢查登錄態是否過期。
通過 wx.login 接口獲得的用戶登錄態擁有一定的時效性。用戶越久未使用小程序,用戶登錄態越有可能失效。反之如果用戶一直在使用小程序,則用戶登錄態一直保持有效。具體時效邏輯由微信維護,對開發者透明。開發者只需要調用 wx.checkSession 接口檢測當前用戶登錄態是否有效。
登錄態過期后開發者可以再調用 wx.login 獲取新的用戶登錄態。調用成功說明當前 session_key 未過期,調用失敗說明 session_key 已過期。更多使用方法詳見 小程序登錄。
參數
Object object
屬性 | 類型 | 默認值 | 必填 | 說明 |
---|---|---|---|---|
success | function | 否 | 接口調用成功的回調函數 | |
fail | function | 否 | 接口調用失敗的回調函數 | |
complete | function | 否 | 接口調用結束的回調函數(調用成功、失敗都會執行) |
示例代碼
wx.checkSession({
success() {
// session_key 未過期,並且在本生命周期一直有效
},
fail() {
// session_key 已經失效,需要重新執行登錄流程
wx.login() // 重新登錄
}
})
微信官方:你要獲取用的信息?我告訴你哈,如果要獲取的話,要經過用戶同意的。
我的回復:sb,我怎么知道他是否授權過呢?如果沒有授權,我怎么讓他授權?
微信官方:你好,你可以調用wx.getSetting來判斷,用戶是否授權,如果沒有授權,你要讓他點擊按鈕,調起授權頁面。用戶點擊同意授權以后*,你就可以調用wx.getUserInfo接口獲取數據了
我的回復:媽的,怎么這么麻煩?
微信官方:對不起,大佬,沒有辦法啊,我們要保護用戶的信息安全啊
我的回復:哦
2.2wx.getSetting(Object object)
基礎庫 1.2.0 開始支持,低版本需做兼容處理。
獲取用戶的當前設置。返回值中只會出現小程序已經向用戶請求過的權限。
參數
Object object
屬性 | 類型 | 默認值 | 必填 | 說明 |
---|---|---|---|---|
success | function | 否 | 接口調用成功的回調函數 | |
fail | function | 否 | 接口調用失敗的回調函數 | |
complete | function | 否 | 接口調用結束的回調函數(調用成功、失敗都會執行) |
object.success 回調函數
參數
Object res
屬性 | 類型 | 說明 |
---|---|---|
authSetting | AuthSetting | 用戶授權結果 |
示例代碼
wx.getSetting({
success(res) {
console.log(res.authSetting)
//部分結果,如果為true,則表示該用戶對這項權限以及授權,如果沒有授權,我們這需要通過button按鈕讓用戶授權
// res.authSetting = {
// "scope.userInfo": true,
// "scope.userLocation": true
// }
}
})
注意事項
wx.authorize({scope: "scope.userInfo"})
,不會彈出授權窗口,請使用<button_open-type="getUserInfo">
- 需要授權
scope.userLocation
時必須配置地理位置用途說明。
微信官方:當你小程序端調用我們wx.getUserInfo的時候,我們會返回你用的基本信息。
我的回復:什么是基本信息,哪些是敏感信息?我后端怎么獲取呢?
微信官方:比如openid這些,大佬,你又兩種方法,第一:你可以將這些基本信息傳到后端,第二: 你可以講getUserInfo中的 iv,encryptedData傳給后端解密,機密后就能獲取到用戶的敏感信息了
我的回復:好的,我后端怎么解密呢?用什么解密呢?
微信官方:你登入的時候不是,后端不是存了session_key嗎?加上這些數據,就可以解密了
我的回復:哦
2.3wx.getUserInfo(Object object)
調用前需要 用戶授權 scope.userInfo。
獲取用戶信息。
參數
Object object
屬性 | 類型 | 默認值 | 必填 | 說明 |
---|---|---|---|---|
withCredentials | boolean | 否 | 是否帶上登錄態信息。當 withCredentials 為 true 時,要求此前有調用過 wx.login 且登錄態尚未過期,此時返回的數據會包含 encryptedData, iv 等敏感信息;當 withCredentials 為 false 時,不要求有登錄態,返回的數據不包含 encryptedData, iv 等敏感信息。 | |
lang | string | en | 否 | 顯示用戶信息的語言 |
success | function | 否 | 接口調用成功的回調函數 | |
fail | function | 否 | 接口調用失敗的回調函數 | |
complete | function | 否 | 接口調用結束的回調函數(調用成功、失敗都會執行) |
object.lang 的合法值
值 | 說明 |
---|---|
en | 英文 |
zh_CN | 簡體中文 |
zh_TW | 繁體中文 |
object.success 回調函數
參數
Object res
屬性 | 類型 | 說明 |
---|---|---|
userInfo | UserInfo | 用戶信息對象,不包含 openid 等敏感信息 |
rawData | string | 不包括敏感信息的原始數據字符串,用於計算簽名 |
signature | string | 使用 sha1( rawData + sessionkey ) 得到字符串,用於校驗用戶信息,詳見 用戶數據的簽名驗證和加解密 |
encryptedData | string | 包括敏感數據在內的完整用戶信息的加密數據,詳見 用戶數據的簽名驗證和加解密 |
iv | string | 加密算法的初始向量,詳見 用戶數據的簽名驗證和加解密 |
接口調整說明
在用戶未授權過的情況下調用此接口,將不再出現授權彈窗,會直接進入 fail 回調(詳見《公告》)。在用戶已授權的情況下調用此接口,可成功獲取用戶信息。
示例代碼
// 必須是在用戶已經授權的情況下調用
wx.getUserInfo({
success(res) {
const userInfo = res.userInfo
const nickName = userInfo.nickName
const avatarUrl = userInfo.avatarUrl
const gender = userInfo.gender // 性別 0:未知、1:男、2:女
const province = userInfo.province
const city = userInfo.city
const country = userInfo.country
}
})
encryptedData 解密后為以下 json 結構,詳見加密數據解密算法
{
"openId": "OPENID",
"nickName": "NICKNAME",
"gender": GENDER,
"city": "CITY",
"province": "PROVINCE",
"country": "COUNTRY",
"avatarUrl": "AVATARURL",
"unionId": "UNIONID",
"watermark": {
"appid": "APPID",
"timestamp": TIMESTAMP
}
}
示例代碼
<!-- 如果只是展示用戶頭像昵稱,可以使用 <open-data /> 組件 -->
<open-data type="userAvatarUrl"></open-data>
<open-data type="userNickName"></open-data>
<!-- 需要使用 button 來授權登錄 -->
<button
wx:if="{{canIUse}}"
open-type="getUserInfo"
bindgetuserinfo="bindGetUserInfo"
>
授權登錄
</button>
<view wx:else>請升級微信版本</view>
Page({
data: {
canIUse: wx.canIUse('button.open-type.getUserInfo')
},
onLoad() {
// 查看是否授權
wx.getSetting({
success(res) {
if (res.authSetting['scope.userInfo']) {
// 已經授權,可以直接調用 getUserInfo 獲取頭像昵稱
wx.getUserInfo({
success(res) {
console.log(res.userInfo)
wx.request({
url: url,
data: {
'iv': res.iv,
'encryptedData': res.encryptedData,
'login_key':登入標識
},
method: "POST",
header: {
'content-type': 'application/json' // 默認值
},
success: function (res) {
//解密后數據
console.log(res);
}
});
}
})
}
}
})
},
bindGetUserInfo(e) {
console.log(e.detail.userInfo)
}
})
叫你解密大法
2.4開放數據校驗與解密
小程序可以通過各種前端接口獲取微信提供的開放數據。考慮到開發者服務器也需要獲取這些開放數據,微信會對這些數據做簽名和加密處理。開發者后台拿到開放數據后可以對數據進行校驗簽名和解密,來保證數據不被篡改。
簽名校驗以及數據加解密涉及用戶的會話密鑰 session_key。 開發者應該事先通過 wx.login 登錄流程獲取會話密鑰 session_key 並保存在服務器。為了數據不被篡改,開發者不應該把 session_key 傳到小程序客戶端等服務器外的環境。
數據簽名校驗
為了確保開放接口返回用戶數據的安全性,微信會對明文數據進行簽名。開發者可以根據業務需要對數據包進行簽名校驗,確保數據的完整性。
- 通過調用接口(如 wx.getUserInfo)獲取數據時,接口會同時返回 rawData、signature,其中 signature = sha1( rawData + session_key )
- 開發者將 signature、rawData 發送到開發者服務器進行校驗。服務器利用用戶對應的 session_key 使用相同的算法計算出簽名 signature2 ,比對 signature 與 signature2 即可校驗數據的完整性。
如 wx.getUserInfo的數據校驗:
接口返回的rawData:
{
"nickName": "Band",
"gender": 1,
"language": "zh_CN",
"city": "Guangzhou",
"province": "Guangdong",
"country": "CN",
"avatarUrl": "http://wx.qlogo.cn/mmopen/vi_32/1vZvI39NWFQ9XM4LtQpFrQJ1xlgZxx3w7bQxKARol6503Iuswjjn6nIGBiaycAjAtpujxyzYsrztuuICqIM5ibXQ/0"
}
用戶的 session-key:
HyVFkGl5F5OQWJZZaNzBBg==
用於簽名的字符串為:
{"nickName":"Band","gender":1,"language":"zh_CN","city":"Guangzhou","province":"Guangdong","country":"CN","avatarUrl":"http://wx.qlogo.cn/mmopen/vi_32/1vZvI39NWFQ9XM4LtQpFrQJ1xlgZxx3w7bQxKARol6503Iuswjjn6nIGBiaycAjAtpujxyzYsrztuuICqIM5ibXQ/0"}HyVFkGl5F5OQWJZZaNzBBg==
使用sha1得到的結果為
75e81ceda165f4ffa64f4068af58c64b8f54b88c
加密數據解密算法
接口如果涉及敏感數據(如wx.getUserInfo
當中的 openId 和 unionId),接口的明文內容將不包含這些敏感數據。開發者如需要獲取敏感數據,需要對接口返回的加密數據(encryptedData) 進行對稱解密。 解密算法如下:
- 對稱解密使用的算法為 AES-128-CBC,數據采用PKCS#7填充。
- 對稱解密的目標密文為 Base64_Decode(encryptedData)。
- 對稱解密秘鑰 aeskey = Base64_Decode(session_key), aeskey 是16字節。
- 對稱解密算法初始向量 為Base64_Decode(iv),其中iv由數據接口返回。
微信官方提供了多種編程語言的示例代碼(點擊下載)。每種語言類型的接口名字均一致。調用方式可以參照示例。
另外,為了應用能校驗數據的有效性,會在敏感數據加上數據水印( watermark )
watermark參數說明:
參數 | 類型 | 說明 |
---|---|---|
appid | String | 敏感數據歸屬 appId,開發者可校驗此參數與自身 appId 是否一致 |
timestamp | Int | 敏感數據獲取的時間戳, 開發者可以用於數據時效性校驗 |
如接口 wx.getUserInfo
敏感數據當中的 watermark:
{
"openId": "OPENID",
"nickName": "NICKNAME",
"gender": GENDER,
"city": "CITY",
"province": "PROVINCE",
"country": "COUNTRY",
"avatarUrl": "AVATARURL",
"unionId": "UNIONID",
"watermark": {
"appid": "APPID",
"timestamp": TIMESTAMP
}
}
注:
- 解密后得到的json數據根據需求可能會增加新的字段,舊字段不會改變和刪減,開發者需要預留足夠的空間
會話密鑰 session_key 有效性
開發者如果遇到因為 session_key 不正確而校驗簽名失敗或解密失敗,請關注下面幾個與 session_key 有關的注意事項。
- wx.login 調用時,用戶的 session_key 可能會被更新而致使舊 session_key 失效(刷新機制存在最短周期,如果同一個用戶短時間內多次調用 wx.login,並非每次調用都導致 session_key 刷新)。開發者應該在明確需要重新登錄時才調用 wx.login,及時通過 code2Session 接口更新服務器存儲的 session_key。
- 微信不會把 session_key 的有效期告知開發者。我們會根據用戶使用小程序的行為對 session_key 進行續期。用戶越頻繁使用小程序,session_key 有效期越長。
- 開發者在 session_key 失效時,可以通過重新執行登錄流程獲取有效的 session_key。使用接口 wx.checkSession可以校驗 session_key 是否有效,從而避免小程序反復執行登錄流程。
- 當開發者在實現自定義登錄態時,可以考慮以 session_key 有效期作為自身登錄態有效期,也可以實現自定義的時效性策略。