本小程序的计算器带有历史记录功能,也就是每个用户都有自己的历史记录,因此需要存储用户信息,用于识别用户。这就少不了获取用户的Openid,因为这是用户的唯一标识符,除此之外,我们还需要获取用户名及头像信息。
整体的流程为:
- 用户登录,前端获取到code,将code传给服务器后端
- 服务器后端用code,AppId和AppSecret到微信指定的API中换取用户Openid,若是新用户,则新建一个用户,存储该Openid
- 后端将该用户的Openid传给前端,同时前端获取到该用户的用户名,并将用户名和Openid传给后端,存储用户名
微信官方文档推荐的流程是在前端获取到加密数据encryptedData、初始向量iv、code,然后将他们一起传给后端,后端利用code获取到session_key,最后利用iv和session_key,解密encryptedData,从而获取到包含Openid和用户名等的所有信息。这样的好处是无需在前端和后端来回传送多次数据,但由于本小程序只需要Openid和用户名,因此不必那么麻烦解密数据。
用户登录,获取code并传给后端
app.js
App({
globalData: {
userInfo: null, //存储用户信息
openid: null //存储openid
},
onLaunch: function () {
var that = this;
// 登录
wx.login({
success: res => {
wx.request({
url: 'https://www.******/getopenid',
data: {
code: res.code
},
success:function(result){
if(result.data != 'none'){
that.globalData.openid = result.data;
}else{
wx.showToast({
title: '登录失败',
icon: 'none',
duration: 1500,
})
}
},
fail:function(){
wx.showToast({
title: '网络错误',
icon: 'none',
duration: 1500
})
}
})
},
fail:function(){
wx.showToast({
title: '网络错误',
icon: 'none',
duration: 1500,
})
}
})
}
})
建立用户模型,用于存储用户Openid和用户名
models.py
from django.db import models
class User(models.Model):
openid = models.CharField(max_length=20)
nickname = models.CharField(max_length=20,default='匿名')
def __str__(self):
return self.nickname
获取openid并传给前端
views.py
from django.conf import settings
from django.http import HttpResponse
from .models import User,Record
import urllib.request,json
def getOpenid(request):
code = request.GET.get('code')
url = 'https://api.weixin.qq.com/sns/jscode2session?appid=%s&secret=%s&js_code=%s&grant_type=authorization_code' % (settings.APPID,settings.APPSECRET,code)
response = urllib.request.urlopen(url)
result = json.loads(response.read().decode('utf-8'))
openid = result.get('openid')
if openid:
users = User.objects.filter(openid=openid)
if not users:
user = User(openid=openid)
user.save()
else:
openid = 'none'
return HttpResponse(openid)
在欢迎页获取用户信息,并存储在globalData中。在此过程中需要用户授权,若用户之前已经授权,则直接使用wx.getUserInfo方法获取用户信息,若用户未授权,则弹出模态框,询问用户是否授权,若同意授权,则从open-type为getUserInfo的button绑定的回调函数返回的结果中获取用户信息。最后获取到用户信息之后才跳转到计算页面。
index.js
const app = getApp()
Page({
data: {
motto: '欢迎使用迷你计算器',
userInfo: {},
hasUserInfo: false,
showModel:false
},
onLoad: function () {
//检测用户是否已经授权
wx.getSetting({
success: res => {
if (res.authSetting['scope.userInfo']) {
// 已经授权,可以直接调用 getUserInfo 获取头像昵称,不会弹框
wx.getUserInfo({
success: res => {
app.globalData.userInfo = res.userInfo //存储用户信息
this.setData({
userInfo: res.userInfo,
hasUserInfo: true
});
}
})
this.redirect();
} else { //未授权,则弹出模态框,询问用户授权
this.setData({
showModel:true
});
}
}
})
},
closeModel:function(e){
this.setData({
showModel:false
});
},
getUserInfo: function(e) { //获取用户信息
if (e.detail.userInfo){
app.globalData.userInfo = e.detail.userInfo;
this.setData({
userInfo: e.detail.userInfo,
hasUserInfo: true
});
this.redirect();
}else{
this.setData({
motto: '请先同意授权,才能使用本小程序',
userInfo: {
avatarUrl:'no.jpg'
}
})
}
},
redirect:function(){ //跳转页面至计算页面
var setTimeoutId = setTimeout(function(){
wx.redirectTo({
url: '../cal/cal',
});
},1500);
}
})
由于微信的模态框无法加入按钮,所以需要模态框需要自己写一个,并附带上open-type为getUserInfo的button。模态框用绝对定位布局即可实现,利用z-index,在模态框的底下一层加一个覆盖全屏的遮罩,并使模态框和遮罩同时显示和隐藏。
index.wxml
<view class="container">
<view class="cover">
<image src="{{userInfo.avatarUrl}}" class="userinfo-avatar" mode="cover"></image>
</view>
<text>{{userInfo.nickName}}</text>
<view class="model" wx:if="{{showModel}}">
<view class="modelTitle">微信授权</view>
<view class="modelBody">微信登录需要获取你的用户信息,请前往授权</view>
<view class="btns">
<button open-type="getUserInfo" class="getInfo_button" bindgetuserinfo='getUserInfo' bindtap='closeModel'>去授权</button>
</view>
</view>
<view class="mask" wx:if="{{showModel}}"></view>
<view class="usermotto">
<text class="user-motto">{{motto}}</text>
</view>
</view>
效果如下: