1. 程式人生 > 程式設計 >微信小程式後端實現授權登入

微信小程式後端實現授權登入

登入與授權

官方文件

一.登入登入流程時序

微信小程式後端實現授權登入

說明:

呼叫

  1. wx.login()獲取臨時登入憑證code,並回傳到開發者伺服器。
  2. 呼叫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":"缺少引數"})

到此這篇關於微信小程式後端實現授權登入的文章就介紹到這了,更多相關微信小程式 授權登入內容請搜尋我們以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援我們!