ChasenKaos原创文章,转载请注明出处。
根据官方api的显示,小程序的登录流程如下:
1、用户打开小程序,后台自动获取code
2、开发者把"code"发送到服务器。
3、服务器把"code"、appid、secret等信息发送到微信官方接口。
4、官方返回一个session_key和用户唯一的身份表示openid。
5、开发者通过官方返回的数据生成私有认证token。
6、将token返回至客户端。
7、用户每次请求携带token。
完整代码如下(node):
1、小程序app.js代码
//app.js
//app.js
App({
onLaunch: function() {
// 展示本地存储能力
var logs = wx.getStorageSync('logs') || []
logs.unshift(Date.now())
wx.setStorageSync('logs', logs)
// 获取用户信息
wx.getSetting({
success: res => {
if (res.authSetting['scope.userInfo']) {
// 已经授权,可以直接调用 getUserInfo 获取头像昵称,不会弹框
wx.getUserInfo({
success: res => {
// 可以将 res 发送给后台解码出 unionId
this.globalData.userInfo = res.userInfo
// 由于 getUserInfo 是网络请求,可能会在 Page.onLoad 之后才返回
// 所以此处加入 callback 以防止这种情况
if (this.userInfoReadyCallback) {
this.userInfoReadyCallback(res)
}
}
})
}
}
})
},
globalData: {
userInfo: null
},
globalApi: {
checkUser: 'http://localhost:4000/checkUser/'
},
getToken() {
return new Promise((resolve, reject) => {
// 登录
wx.login({
success: res => {
// 发送 res.code 到后台换取 openId, sessionKey, unionId
if (res.code) {
//发送res.code 到后台
wx.request({
url: this.globalApi.checkUser,
method: 'POST',
data: {
code: res.code
},
success(res) {
//成功返回数据后,将token值存储到localStorage中
wx.setStorage({
key: 'yerlLocalToken',
data: res.data.token
});
var resArg = res.data.token;
resolve()
},
fail() {
reject();
}
})
}
}
})
})
}
})
我是在本地环境测试的,所以api用的是本地地址,我把它放到了globalApi中方便调用。
2、小程序的页面中调用token
///index.js
//获取应用实例
const app = getApp()
Page({
data: {
token:''
},
onLoad() {
let that = this;
app.getToken().then(function(){
that.setData({
token: wx.getStorageSync('yerlLocalToken')
});
console.log(that.data.token)
});
}
})
3、后台(node + express + mongodb)
//express
const express = require('express');
const router = express.Router();
//处理formdata
const bodyParser = require('body-parser');
const jsonParser = bodyParser.json();
const urlencodedParser = bodyParser.urlencoded({
extended: false
});
//处理node request请求
const request = require('request');
//token
const jwt = require('./jwt.js'); //这个是jsonwebtoken中的方法,我又进行了二次加工。
//微信小程序设置
const wx = require('./wxconfig.json'); //文件中存储了appid 和 secret
//数据库
const datebase = require('./dbconfig.json') //文件中存储了数据库地址
const mongodb = require('mongodb');
const MongoClient = mongodb.MongoClient;
//路由
router.post('/', urlencodedParser, (req, res) => {
//拿到前台给的code后,发送请求
if(req.body.code) {
let options = {
method: 'POST',
url: 'https://api.weixin.qq.com/sns/jscode2session?',
formData: {
appid: wx.appid,
secret: wx.secret,
js_code: req.body.code,
grant_type: 'authorization_code'
}
};
request(options, (error, response, body) => {
if(error) { //请求异常时,返回错误信息
res.json({
"status": "error",
"code": "ChasenKaso原创文章,转载请注明出处"
})
} else {
//返回值的字符串转JSON
let _data = JSON.parse(body);
//根据返回值创建token
let _l = jwt.createHoursToken(req.body.code, _data.openid, _data.session_key);
let _s = jwt.createMonthToken(req.body.code, _data.openid, _data.session_key);
//连接数据库
MongoClient.connect(datebase.url, (err, client) => {
if(err) {
res.json({
"status": "error",
"code": "0002"
});
client.close();
} else {
const users = client.db(datebase.db).collection('Users'); //查询数据库中是否有当前的openid
users.count({
"openid": _data.openid
}, (err, result) => {
//当数据库中没有该openid时,插入。
if(result == 0) {
users.insert({
"openid": _data.openid,
"localToken": _l,
"serverToken": _s
}, (err, result) => {
res.json({
"status": "ok",
"token": _l
});
client.close();
})
};
//当数据库中查询到openid时,更新token
if(result != 0) {
users.update({
"openid": _data.openid
}, {
$set: {
"localToken": _l,
"serverToken": _s
}
}, (err, result) => {
if(err) {
res.json({
"status": "error",
"code": "0003"
});
client.close();
} else {
res.json({
"status": "ok",
"token": _l
});
client.close();
}
})
}
})
}
})
}
});
} else {
res.json({
"status": "error",
"code": "0004"
});
}
})
module.exports = router;
在主程序中调用这个router就可以了,代码如下:
const checkUser = require('./router/checkUser.js');
app.use('/checkUser',checkUser)
运行后,显示如下:
调试台已经显示了后台返回的token。
我把app.js中的用户登录使用promise进行了封装,这样可以让我在运行小程序并打开index页面时,可以正常显示token,否则会出现异步登录未成功,页面就已经渲染完成,无法获取到token的现象。