03-05 微信用户授权登入获取用户信息

______egon新书python全套来袭请看:https://egonlin.com/book.html

微信用户授权登入获取用户信息

需求:后端获取该用户的详情信息。保存至后台数据库,前端也要获取用户信息。

小程序端

1 必须保证用户是授权的,小程序端就可以获取非敏感信息,且要保证用户的后端保存的session_key是有效状态,将授权后的 iv,encryptedData,login_key传给后端。

app.josn

  {
  "pages": [
    "pages/list/list",
    "pages/item/item",
    "pages/login/login"
  ],
  "window": {
    "backgroundTextStyle": "light",
    "navigationBarBackgroundColor": "#e50e38",
    "navigationBarTitleText": "百步生活",
    "navigationBarTextStyle": "#fff",
    "enablePullDownRefresh": false,
    "backgroundColor": "#e50e38"
  },
}
  

app.js

App({
    onLaunch: function () {
    // 展示本地存储能力001bHJ281qo7rS1JR1481OQC281bHJ2B
    var _this = this;  
      wx.login({
        success: res => {
         // console.log(res);
          wx.request({
            url: _this.globalData.apiDomain +'/api/member/code/login',
            data: {
              code: res.code
            },
            method: "POST",
            header: {
              'content-type': 'application/json' // 默认值
            },
            success: function (res) {
              console.log(res);
              wx.setStorageSync('login_key', res.data.data.login_key);
            },
            fail:function(res){
              console.log(res)
            }
          })
        }
      });
  },
  //设置全局的变量,apiDomain这是我们接口的ip
  globalData: {
    apiDomain:'http://127.0.0.1:8000',
    //保存当前用户的基本信息
    userInfo: null,
    login_key:''
  }
})

login.wxml

<view class="container">
    <image class="avatar" src="../../images/purplebox.jpg"></image>
    <view class="name">百步有礼</view>
    <view class="agree">请同意授权</view>
    <view class="author">·以便百步有礼为你提供更好的服务</view>
    <button  open-type="getUserInfo" bindgetuserinfo="getUserInfo">登录</button>    
</view>

login.wxss

button{
  margin-top:60rpx;
width:590rpx;
background:#51a938;
color:#fff;
}
.container{
  padding-top: 100rpx;
}
.avatar{
  width:180rpx;
  height:180rpx;
  border-radius:50%;
  border:2rpx solid #eee;
}
.name{
  padding-top:12rpx;
  font-size:36rpx;
  font-weight:bolder;
}
.agree{
  margin-top:120rpx;
text-align:left;
width:670rpx;
padding-left:80rpx;
font-weight:bolder;
font-size:30rpx;
}
.author{
  line-height:90rpx;
font-size:30rpx;
width:670rpx;
text-align:left;
padding-left:80rpx;

}

login.json

{
  "navigationBarBackgroundColor": "#fff",
  "navigationBarTitleText": "授权登录",
  "navigationBarTextStyle": "black"
}

login.js

//获取应用实例
const app = getApp();

Page({
  data: {

  },
  getUserInfo: function (e) {
    if(e.detail.userInfo){
      var _this = this;
      app.globalData.userInfo = e.detail.userInfo
      this.setData({
        userInfo: e.detail.userInfo,
        hasUserInfo: true
      });
      wx.request({
        url: app.globalData.apiDomain+'/api/member/code/getUserInfo',
        data: {
          'iv': e.detail.iv,
          'encryptedData': e.detail.encryptedData,
          'login_key': wx.getStorageSync('login_key')
        },
        method: "POST",
        header: {
          'content-type': 'application/json' // 默认值
        },
        success: function (res) {
          wx.navigateBack({
              delta: 1
          })
        }
      });
    };
    
  },
 
})

服务端

1接收 iv,encryptedData,login_key,通过login_key取出session_key和openid。通过调用微信接口,获取解密数据。

2 获取成功后,更新当前用户的详细信息,并可以将敏感信息传递给前端

url.py

from django.contrib import admin
from django.urls import path
from django.conf.urls import url
from api.views import product,user

urlpatterns = [
    path('admin/', admin.site.urls),
    url(r'^api/indexlist/categoryList$', product.caetgoryList.as_view()),
    url(r'^api/indexlist/IndexProductList$', product.ProductList.as_view()),
    url(r'^api/indexlist/categoryProductsList$', product.categoryProductsList.as_view()),
    url(r'^api/indexlist/detailProduct$', product.detailProduct.as_view()),
    url(r'^api/member/code/login$', user.login.as_view()),
    url(r'^api/member/code/getUserInfo$', user.getUserInfo.as_view()),
]

user.py

from django.shortcuts import render,HttpResponse
from rest_framework.views import APIView
from api.wx import wxlogin,UserInfo,setting
from api import baseResponse
import time
from django.core.cache import cache #引入缓存模块
from api import models
from django.http import JsonResponse
import hashlib
# Create your views here.
class login(APIView):
    def post(self,request):
        # 用apiview之后,再取数据,从request.data
        params=request.data
        #判断前端是否传入code参数
        if params.get('code'):
            code=params['code']
            #调用wxloing.getLoginInfo获取session_key和openid
            user_data=wxlogin.getLoginInfo(code)
            if user_data:
                #将session_key和openid拼接成字符串,不要乱选拼接字符串,因为openid中有特殊符号
                val=user_data['session_key']+'&'+user_data['openid']
                #生成MD5值获取key
                md=hashlib.md5()
                md.update(code.encode('utf-8'))
                md.update(str(time.clock()).encode('utf-8'))
                key = md.hexdigest()
                data={}
                try:
                    #将key和上面的val存入redis
                    cache.set(key,val)
                    #返回login_key到小程序
                    data['login_key'] = key
                    #将用户数据存入数据库
                    try:
                        user = models.Wxuser.objects.get(openid=user_data['openid'])
                    except Exception as e:
                        user=None
                    #如果数据没有则创建记录
                    if not user:
                        models.Wxuser.objects.create(openid=user_data['openid'])
                    re_data = baseResponse.resdic("success", "成功",data )
                    return JsonResponse(re_data)
                except Exception as e:
                    print(e)
                    re_data = baseResponse.resdic("error", "redis程序出错" )
                    return JsonResponse(re_data)
            else:
                re_data = baseResponse.resdic("error", "获取session_key失败")
                return JsonResponse(re_data)
        else:
            re_data = baseResponse.resdic("error", "缺少参数")
            return JsonResponse(re_data)


class getUserInfo(APIView):
    def post(self,request):
        params = request.data
        #判断小程序是否传入这些参数
        if params.get('encryptedData') and params.get('iv') and params.get('login_key'):
            encryptedData =params['encryptedData']
            iv = params['iv']
            login_key = params['login_key']
            data=cache.get(login_key)
            #判断login_key是否过期
            if not data:
                re_data = baseResponse.resdic("error", "login_key已过期")
                return JsonResponse(re_data)
            #将字符串分成列表
            data_list=data.split('&')
            #pc = WXBizDataCrypt(appId, sessionKey)
            print(data_list)
            try:
                #调用 UserInfo.WXBizDataCrypt,obj.decrypt解密数据
                use_class = UserInfo.WXBizDataCrypt(setting.AppId, data_list[0])
                user_info=use_class.decrypt(encryptedData, iv)
            except Exception as e:
                re_data = baseResponse.resdic("error", "解密失败")
                return JsonResponse(re_data)
            #解密成功后组织存入数据库数据,
            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'],
                'gender':user_info['gender'],
            }

            # models.Wxuser.objects.filter(openid=data_list[1]).update(name=user_info['nickName'],
            #                                                          avatar=user_info['avatarUrl'],
            #                                                          language=user_info['language'],
            #                                                          province=user_info['province'],
            #                                                          city=user_info['city'],
            #                                                          country=user_info['country'],
            #                                                          gender=user_info['gender'])
            #更新当前用户的数据
            models.Wxuser.objects.filter(openid=data_list[1]).update(**save_data)
            #将解密后的数据返回小程序。
            re_data = baseResponse.resdic("success", "成功",user_info)

            return JsonResponse(re_data)
            #解密获取用户信息

        else:
            re_data = baseResponse.resdic("error", "缺少参数")
            return JsonResponse(re_data)

api.wx.UserInfo.py

import base64
import json
from Crypto.Cipher import AES

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:])]
posted @ 2019-10-14 12:08  小猿取经-林海峰老师  阅读(758)  评论(2编辑  收藏  举报