小程序session_key失效解決方案、后台解密個人數據信息


一、登錄會話密鑰 session_key 有效性

https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/signature.html

開發者如果遇到因為 session_key 不正確而校驗簽名失敗或解密失敗,請關注下面幾個與 session_key 有關的注意事項。

  1. wx.login 調用時,用戶的 session_key 可能會被更新而致使舊 session_key 失效(刷新機制存在最短周期,如果同一個用戶短時間內多次調用 wx.login,並非每次調用都導致 session_key 刷新)。開發者應該在明確需要重新登錄時才調用 wx.login,及時通過 auth.code2Session 接口更新服務器存儲的 session_key。
  2. 微信不會把 session_key 的有效期告知開發者。我們會根據用戶使用小程序的行為對 session_key 進行續期。用戶越頻繁使用小程序,session_key 有效期越長。
  3. 開發者在 session_key 失效時,可以通過重新執行登錄流程獲取有效的 session_key。使用接口 wx.checkSession可以校驗 session_key 是否有效,從而避免小程序反復執行登錄流程。
  4. 當開發者在實現自定義登錄態時,可以考慮以 session_key 有效期作為自身登錄態有效期,也可以實現自定義的時效性策略。

二、解決登錄session_key 的問題

通過wx.checkSession判斷是否過期。

第一步:在生命周期中onLaunch調用一次寫的登錄方法
第二步:在其他地方通過wx.checkSession判斷是否過期,如果過期再次調用登錄方法,更新session_key 

案例:解決session_key 過期問題,發送個人信息后台解密

# app.js中:
//app.js
App({

  /*
    當小程序初始話完成,會觸發onlaunch(全局只觸發一次)
  */
  onLaunch: function () {
    // 登錄
    this.my_login()
    

  },
  my_login:function(){
    let that = this
    wx.login({
      success: res => {
        // 發送 res.code 到后台換取 openId, sessionKey, unionId
        console.log(res.code)
        wx.request({
          url: that.globalData.baseurl + "login/",
          data: { "code": res.code },
          method: "POST",
          success(e) {
            wx.setStorageSync('token', e.data.data.token)
          }
        })
      }
    })
  },
  globalData: {
    userInfo: null,
    baseurl:"http://127.0.0.1:8000/"
  }
})


# 頁面js中:

// 先拿到app全局對象
const app = getApp()

user1:function (e) {
    
    wx.getSetting({
      success(res) {
        if (res.authSetting['scope.userInfo']) {
         
          wx.getUserInfo({
            success: (res) => {
              console.log("res",res) //這個res就是用戶的信息
              // 將數據發送后端
              wx.request({
                // 發送iv,encryptedData
                url: app.globalData.baseurl + "getinfo/",
                data:{
                  iv:res.iv,
                  encryptedData: res.encryptedData,
                  token:wx.getStorageSync("token")
                },
                method:"POST",
                success:(e) =>{
                  console.log('后台返回的數據',e)
                }
              })
            },
          })
		
            
          // 判斷是否過期
          wx.checkSession({
            success() {
              //session_key 未過期,並且在本生命周期一直有效
            },
            fail() {
              // session_key 已經失效,需要重新執行登錄流程
              app.my_login() // 重新登錄,更新session_key
			
              wx.getUserInfo({
                success: (res) => {
                  console.log("res啦啦啦", res) //這個res就是用戶的信息
                  // 將數據發送后端
                  wx.request({
                    // 發送iv,encryptedData
                    url: 'url',
                  })
                },
              })
            }
          })
        }
      }
    })
    
  }

后端解密信息,存入數據庫

# 登錄:略
# urls.py
path('getinfo/', user.Info.as_view()),


# user.py
from django.core.cache import cache
from api.models import Wxuser
from api.wx import WXBizDataCrypt
from api.my_ser import wx_user_ser
from rest_framework.response import Response

class Info(APIView):
    def post(self, request):
        param = request.data
        if param['iv'] and param.get("token") and param.get("encryptedData"):
            iv = param['iv']
            encryptedData = param.get("encryptedData")
            session_key_openid = cache.get(param.get("token"))
            if session_key_openid:
                sessionKey, openid = session_key_openid.split("&")
                # 解密
                user_info = WXBizDataCrypt.WXBizDataCrypt.get_info(sessionKey, encryptedData, iv)
                print('user_info', user_info)
                save_data = {
                    "name": user_info['nickName'],
                    "avatar": user_info['avatarUrl'],
                    "language": user_info['language'],
                    "province": user_info['province'],
                    "city": user_info['city'],
                    "country": user_info['country'],
                }
                # 把用戶信息存入數據庫
                Wxuser.objects.filter(openid=openid).update(**save_data)
                # 測試:把童虎信息返回給前台
                user = Wxuser.objects.filter(openid=openid).first()
                user = wx_user_ser(instance=user, many=False).data
                return Response({
                    "status": 0,
                    "msg": "ok",
                    "data": user
                })
            else:
                return Response({"code": 2, "msg": "無效的token"})
        else:
            return Response({"code": 1, "msg": "缺少參數"})
            # 檢測對字典排序
            
            
            
# WXBizDataCrypt文件,下載的解密,然后二次封裝的
import base64
import json
from Crypto.Cipher import AES
from api.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 get_info(cls,sessionKey,encryptedData,iv):
        # appId = settings.AppId
        # sessionKey = sessionKey
        # encryptedData = encryptedData
        # iv = iv
        #
        # # 實例化這個類 WXBizDataCrypt
        # pc = cls(appId, sessionKey)
        # return pc.decrypt(encryptedData, iv)

        # 簡化為:
        return cls(settings.AppId, sessionKey).decrypt(encryptedData, iv)

mysql數據庫存表情設置

1.mysql數據庫類型
2.配置:默認是utf8,3個字節。表情是4個字節,需要設置:'OPTIONS': {'charset': 'utf8mb4'},

import pymysql
pymysql.install_as_MySQLdb()
DATABASES = {
    'default': {
        'ENGINE': 'django.db.backends.mysql',
        'NAME': 'python13',
        'USER': 'root',
        'PASSWORD': '123',
        'HOST': 'localhost',
        'PORT': 3306,
        'OPTIONS': {'charset': 'utf8mb4'},
    }
}

三、后端,如何解析wx.getUserInfor中的用戶信息。

1 我們用encryptedData和iv,進行解密,必須要用到session_key,所以用必須是登入狀態。
2 但是session_key是有有效期。而且session_key的有效期,不是一個固定值,他是通過用戶行為來決定,session_key的有效期時間。
3 但是我們可以通過wx.checkSession來判斷有沒有過期。
4 保證session_key沒有過期的情況下。我們將iv,encryptedData,token(登入憑證)發送到后端.
5 后端使用官方提供的sdk,進行解密。
6 解密成功以后保存到數據,數據庫的字符集一定要是utf8mb4,才能保存表情包


如官方的sdk沒有Crypto包用下面的方法解決:

pip install pycryptodome 

用戶信息官方文檔

https://developers.weixin.qq.com/miniprogram/dev/api/open-api/user-info/wx.getUserInfo.html

數據加密官方文檔

https://developers.weixin.qq.com/miniprogram/dev/framework/open-ability/signature.html


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM