微信小程式後端實現授權登入
登入與授權
官方文件
一.登入登入流程時序
說明:
呼叫
- wx.login()獲取臨時登入憑證code,並回傳到開發者伺服器。
- 呼叫code2Session介面,換取使用者唯一標識 OpenID和會話金鑰 session_key。
之後開發者伺服器可以根據使用者標識來生成自定義登入態,用於後續業務邏輯中前後端互動時識別使用者身份。
注意:
會話金鑰session_key
是對使用者資料進行加密簽名的金鑰。為了應用自身的資料安全,開發者伺服器不應該把會話金鑰下發到小程式,也不應該對外提供這個金鑰。
臨時登入憑證 code 只能使用一次
總結:
小程式端執行wx.login後在回撥函式中就能拿到上圖的code,然後把這個code傳給我們後端程式,後端拿到這個這個code後,可以請求code2Session介面拿到用的openid和session_key,openid是使用者在微信中唯一標識,我們就可以把這個兩個值(val)存起來,然後返回一個鍵(key)給小程式端,下次小程式請求我們後端的時候,帶上這個key,我們就能找到這個val,就可以,這樣就把登入做好了。
wx.login
呼叫介面獲取登入憑證(code)。通過憑證進而換取使用者登入態資訊,包括使用者的唯一標識(openid)及本次登入的會話
金鑰(session_key)等。使用者資料的加解密通訊需要依賴會話金鑰完成。[/code]
引數
屬性 | 型別 | 預設值 | 必填 | 說明 | 最低版本 |
---|---|---|---|---|---|
timeout | number | 否 | 超時時間,單位ms | 1.9.90 | |
success | function | 否 | 介面呼叫成功的回撥函式 | ||
fail | function | 否 | 介面呼叫失敗的回撥函式 | ||
complete | function | 否 | 介面呼叫結束的回撥函式(呼叫成功、失敗都會執行) |
object.success 回撥函式
引數
屬性 | 型別 | 說明 |
---|---|---|
code | string | 使用者登入憑證(有效期五分鐘)。開發者需要在開發者伺服器後臺呼叫code2Session,使用 code 換取 openid 和 session_key 等資訊 |
code2Session
本介面應在伺服器端呼叫,詳細說明參見服務端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次 |
二.資訊授權wx.getUserInfo
獲取使用者資訊。
引數
屬性 | 型別 | 預設值 | 必填 | 說明 |
---|---|---|---|---|
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 回撥函式
引數
屬性 | 型別 | 說明 |
---|---|---|
userInfo | UserInfo | 使用者資訊物件,不包含 openid 等敏感資訊 |
rawData | string | 不包括敏感資訊的原始資料字串,用於計算簽名 |
signature | string | 使用 sha1( rawData + sessionkey ) 得到字串,用於校驗使用者資訊,詳見使用者資料的簽名驗證和加解密 |
encryptedData | string | 包括敏感資料在內的完整使用者資訊的加密資料,詳見使用者資料的簽名驗證和加解密 |
iv | string | 加密演算法的初始向量,詳見使用者資料的簽名驗證和加解密 |
注意:
1.小程式端獲取授權資訊要用button按鈕觸發
2.小程式端需要將 encryptedData,iv,login_key 傳到後端用於解密
案例:
登入:
當小程式第一次執行的時候就呼叫wx.login
小程式端:apps.js
App({ onLaunch: function () { var _this=this // 登入 wx.login({ success: res => { // 傳送 res.code 到後臺換取 openId,sessionKey,unionId wx.request({ url: _this.globalData.Url+'/login/',// 後端路徑 data:{"code":res.code},// code header:{"content-type":"application/json"},method:"POST",success:function(res){ console.log(res) // 小程式端儲存login_key wx.setStorageSync("login_key",res.data.data.login_key) } }) } }) },globalData: { Url:"http://127.0.0.1:8000",userInfo: null } })
後端 django
wx ├── settings.py # 小程式id,code2Session等配置 ├── wx_login.py # 用於呼叫code2Session拿到openid等 └── WXBizDataCrypt.py # 獲取使用者授權資訊的解密演算法,官方下載
微信官方解密演算法程式碼
專案/settings.py
# 配置資料庫 DATABASES = { 'default': { 'ENGINE': 'django.db.backends.mysql','NAME': 'wx','USER':'root','PASSWORD':'root','HOST':'127.0.0.1','PORT': 3306,'OPTIONS': {'charset': 'utf8mb4'},# 微信使用者名稱可能有標籤,所以用utf8mb4 } } # 配置 django-redis CACHES = { 'default': { 'BACKEND': 'django_redis.cache.RedisCache','LOCATION': 'redis://127.0.0.1:6379',"OPTIONS": { "CLIENT_CLASS": "django_redis.client.DefaultClient","PASSWORD": "",},}
wx/settings.py
# 小程式開發者id AppId="..." # 小程式的AppSecret AppSecret="..." code2Session="https://api.weixin.qq.com/sns/jscode2session?appid={}&secret={}&js_code={}&grant_type=authorization_code" pay_mchid ='...' pay_apikey = '...'
wx/wx_login.py
from app01.wx import settings import requests # 呼叫微信code2Session介面,換取使用者唯一標識 OpenID 和 會話金鑰 session_key def login(code): response = requests.get(settings.code2Session.format(settings.AppId,settings.AppSecret,code)) data = response.json() if data.get("openid"): return data else: return False
專案/views.py
from rest_framework.views import APIView from rest_framework.response import Response from app01.wx import wx_login from django.core.cache import cache from app01 import models import time,hashlib class Login(APIView): def post(self,request): param = request.data # 拿到小程式端提交的code if param.get('code'): # 呼叫微信code2Session介面,換取使用者唯一標識 OpenID 和 會話金鑰 session_key data = wx_login.login(param.get('code')) if data: # 將openid 和 session_key拼接 val = data['openid'] + "&" + data["session_key"] key = data["openid"] + str(int(time.time())) # 將 openid 加密 md5 = hashlib.md5() md5.update(key.encode("utf-8")) key = md5.hexdigest() # 儲存到redis記憶體庫,因為小程式端後續需要認證的操作會需要頻繁校驗 cache.set(key,val) has_user = models.Wxuser.objects.filter(openid=data['openid']).first() # 使用者不存在則建立使用者 if not has_user: models.Wxuser.objects.create(openid=data['openid']) return Response({ "code": 200,"msg": "ok","data": {"login_key": key} # 返回給小程式端 }) else: return Response({"code": 401,"msg": "code無效"}) else: return Response({"code": 401,"msg": "缺少引數"})
使用者資訊授權
小程式端test.wxml
<!--使用者資訊授權--> <button open-type="getUserInfo" bindgetuserinfo="info">授權登入</button>
test.js
Page({ info: function (res) { // console.log(res) wx.checkSession({ success() { //session_key 未過期,並且在本生命週期一直有效 wx.getUserInfo({ success: function (res) { // console.log(res) wx.request({ url: app.globalData.Url + "/getinfo/",data: { "encryptedData": res.encryptedData,"iv": res.iv,"login_key": wx.getStorageSync("login_key") },method: "POST",header: { "content-type": "application/json" },success: function (res) { console.log(res) } }) } }) })
後端 django
wx/WXBizDataCrypt.py
import base64 import json from Crypto.Cipher import AES from app01.wx import settings class WXBizDataCrypt: def __init__(self,appId,sessionKey): self.appId = appId self.sessionKey = sessionKey def decrypt(self,encryptedData,iv): # base64 decode sessionKey = base64.b64decode(self.sessionKey) encryptedData = base64.b64decode(encryptedData) iv = base64.b64decode(iv) cipher = AES.new(sessionKey,AES.MODE_CBC,iv) decrypted = json.loads(self._unpad(cipher.decrypt(encryptedData))) if decrypted['watermark']['appid'] != self.appId: raise Exception('Invalid Buffer') return decrypted def _unpad(self,s): return s[:-ord(s[len(s)-1:])] @classmethod def getInfo(cls,session_key): return cls(settings.AppId,session_key).decrypt(encryptedData,iv)
專案/serializer.py
from rest_framework.serializers import ModelSerializer from app01 import models class User_ser(ModelSerializer): class Meta: model=models.Wxuser fields="__all__"
專案/views.py
from app01.wx import WXBizDataCrypt from app01 import serializer from app01 import models class GetInfo(APIView): def post(self,request): param=request.data # 需要小程式端將 encryptedData iv login_key 的值傳到後端 # encryptedData iv seesion_key 用於解密獲取使用者資訊 # login_key 用於校驗使用者登入狀態 if param['encryptedData'] and param['iv'] and param['login_key']: # 從redis中拿到login_key並切分拿到 openid 和 session_key openid,seesion_key=cache.get(param['login_key']).split("&") # 利用微信官方提供演算法拿到使用者的開放資料 data=WXBizDataCrypt.WXBizDataCrypt.getInfo(param['encryptedData'],param['iv'],seesion_key) save_data={ "name":data['nickName'],"avatar":data['avatarUrl'],"language":data['language'],"province":data['province'],"city":data['city'],"country":data['country'],} # 將拿到的使用者資訊更新到使用者表中 models.Wxuser.objects.filter(openid=openid).update(**save_data) # 反序列化使用者物件,並返回到小程式端 data=models.Wxuser.objects.filter(openid=openid).first() data=serializer.User_ser(instance=data,many=False).data return Response({"code":200,"msg":"缺少引數","data":data}) else: return Response({"code":200,"msg":"缺少引數"})
到此這篇關於微信小程式後端實現授權登入的文章就介紹到這了,更多相關微信小程式 授權登入內容請搜尋我們以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援我們!