前言
上个月的加班已经结束了,绩效进行微信小程序商城的开发,后台管理系统初步完成,小程序首页已经展示了商品,下一步就是添加购物车,生成订单;这里就设计到小程序登录。 记载一下自己的实现过程,下次直接copy。
一、实现思路
在添加购物车或着其它需要登录才能进行的操作时,先判断是否登录。进入登录页面,先使用wx.getSetting()方法判断是否授权,如果授权了,直接使用wx.login()获取Code 向后台发送请求,换取openid(下面会讲)。然后再调用wx.getUserInfo()拿到用户信息,调接口更新用户信息,成功后返回之前页面。
如果没有授权,则显示出授权页面,提醒用户点击按钮进行授权,然后重复上面的操作。
二、授权按钮界面
三、前端代码
这里贴的代码是通过uniapp写的,如果是原生写法,只需要做对应的修改即可
<template>
<view class="login">
<view v-if="isCanUse">
<view>
<view class="header"><image src="../../static/wx_login.png"></image></view>
<view class="content">
<view>申请获取以下权限</view>
<text>获得你的公开信息(昵称,头像、地区等)</text>
</view>
<button class="bottom" type="primary" open-type="getUserInfo" withCredentials="true" lang="zh_CN" @getuserinfo="wxGetUserInfo">授权登录</button>
</view>
</view>
<u-toast ref="uToast" />
</view>
</template>
<script>
export default {
name: 'login',
data() {
return {
SessionKey: '',
OpenId: '',
nickName: null,
avatarUrl: null,
isCanUse: uni.getStorageSync('isCanUse') || true //默认为true
};
},
onLoad() {
//默认加载
this.login();
this.isCanUse = uni.getStorageSync('isCanUse');
},
methods: {
//第一授权获取用户信息===》按钮触发
wxGetUserInfo() {
let _this = this;
uni.getUserInfo({
provider: 'weixin',
success: function(infoRes) {
uni.setStorageSync('isCanUse', false); //记录是否第一次授权 false:表示不是第一次授权
_this.userLogin(infoRes.userInfo);
},
fail(res) {
uni.showToast({title:"微信登录授权失败",icon:"none"});
}
});
},
//登录
login() {
let _this = this;
wx.getSetting({
success: function(res) {
if (res.authSetting['scope.userInfo']) {
console.log('用户授权了');
uni.showLoading({
title:"登录中..."
})
uni.setStorageSync('isCanUse', false);//记录是否第一次授权 false:表示不是第一次授权
_this.userLogin();
} else {
//用户没有授权
console.log('用户没有授权');
_this.isCanUse = true;
}
}
});
},
userLogin(data) {
let _this = this;
// 1.wx获取登录用户code
uni.login({
provider: 'weixin',
success: function(loginRes) {
let code = loginRes.code;
//2.将用户登录code传递到后台置换用户SessionKey、OpenId等信息
_this.$api.getOpenId({ code }).then(res => {
uni.hideLoading()
if (!data) {
uni.getUserInfo({
provider: 'weixin',
success: function(infoRes) {
_this.$store.commit('SET_STATE', ['userInfo', infoRes.userInfo]);
//获取用户信息后向调用信息更新方法
_this.updateUserInfo(infoRes.userInfo, res.data); //调用更新信息方法
}
});
} else {
_this.updateUserInfo(data, res.data); //调用更新信息方法
}
});
}
});
},
//向后台更新信息
updateUserInfo(info,openInfo) {
const { avatarUrl, city, country, gender,language, nickName, province} = info
const { _id } = openInfo.data
let _this = this;
this.$api.login({avatarUrl, city, country, gender,language, nickName, province, _id}).then(res=>{
if(res.data.isSuccess){
_this.$store.commit('SET_STATE',['userInfo',res.data.data])
_this.$store.commit('SET_STATE',['token',res.data.data.token])
uni.setStorageSync('token',res.data.data.token)
_this.$refs.uToast.show({
title: '登录成功',
type: 'success',
});
}else{
_this.$refs.uToast.show({
title: '登录失败',
type: 'fail',
});
}
setTimeout(()=>{
uni.navigateBack()
},1500)
})
}
}
};
</script>
<style scoped lang="scss">
.header {
margin: 90upx 0 90upx 50upx;
border-bottom: 1px solid #ccc;
text-align: center;
width: 650upx;
height: 300upx;
line-height: 450upx;
}
.header image {
width: 200upx;
height: 200upx;
}
.content {
margin-left: 50upx;
margin-bottom: 90upx;
}
.content text {
display: block;
color: #9d9d9d;
margin-top: 40upx;
}
.bottom {
border-radius: 80upx;
margin: 70upx 50upx;
font-size: 35upx;
}
</style>
四、node后端代码实现
后台接口采用node+express+mongoose
- 获取openid并创建用户接口
//获取openId的时候,查询用户是否存在,不存在则创建用户,反之更新令牌
var express = require('express');
var router = express.Router();
const User = require('./../model/user')
const { createToken, verifyToken } = require('./../utils')
const { WX_CONFIG } = require('./../utils/config')
// querystring这个模块,用来做url查询参数的解析
const querystring = require('querystring');
const request = require('request');
/**
* @name: 获取微信用户的openId
* @param {string} code 微信小程序授权后返回的code
* @Author: 471826078@qq.com
*/
router.post('/getOpenId', (req, res, next) => {
const data = {
'appid': WX_CONFIG.appId,
'secret': WX_CONFIG.appScrect,
'js_code': req.body.code,
'grant_type': 'authorization_code'
}
// querystring的stringify用于拼接查询
var content = querystring.stringify(data);
// 根据微信开发者文档给的API
var url = 'https://api.weixin.qq.com/sns/jscode2session?' + content;
// 对url发出一个get请求
request.get({
'url': url
}, (error, response, body) => {
// 将body的内容解析出来
let abody = JSON.parse(body);
const { openid, session_key } = abody
if (openid) {
User.findOne({ openId: openid }).exec((err, doc) => {
if (err) {
res.send({ isSuccess: false, message: '登录失败' });
} else {
let token = createToken({ isAdmin: 0, openId: openid, session_key }, 3600 * 24 * 3)
if (!doc) {
new User({ openId: openid, session_key, isAdmin: 0, token }).save((err1, doc) => {
if (err1) {
res.send({ isSuccess: false, message: '登录失败' });
} else {
res.send({ isSuccess: true, message: '登录成功', data: doc });
}
})
} else {
User.findByIdAndUpdate({ _id: doc._id }, { token, session_key }, { new: true }).exec((err2, doc2) => {
if (err2) {
res.send({ isSuccess: false, message: '登录失败' });
} else {
res.send({ isSuccess: true, message: '登录成功', data: doc });
}
})
}
}
})
} else {
res.send({ isSuccess: false, message: '登录失败' });
}
})
})
module.exports = router
授权后更新用户信息接口
//会员注册
var express = require('express');
var router = express.Router();
const User = require('./../model/user')
router.post('/memberRegister', (req, res, next) => {
const { _id, avatarUrl, city, country, gender, language, nickName, province, } = req.body;
User.findByIdAndUpdate({ _id }, { avatarUrl, city, country, gender, language, nickName, province, }, { new: true }).exec((err3, doc) => {
if (err3) {
res.send({ isSuccess: false, message: '登录失败' });
} else {
res.send({ isSuccess: true, message: '登录成功', data: doc });
}
})
})
module.exports = router
五、返回登录之前的页面
if(res.data.isSuccess){
_this.$store.commit('SET_STATE',['userInfo',res.data.data])
_this.$store.commit('SET_STATE',['token',res.data.data.token])
uni.setStorageSync('token',res.data.data.token)
_this.$refs.uToast.show({
title: '登录成功',
type: 'success',
});
}else{
_this.$refs.uToast.show({
title: '登录失败',
type: 'fail',
});
}
setTimeout(()=>{
uni.navigateBack()
},1500)
// SET_STATE 方法
const mutations = {
SET_STATE(state, e) {
if (e) {
state[e[0]] = e[1];
}
},
}
export default mutations;