项目
- 某电影票务项目(Vue微信公众号项目)
总结:作为离职前的项目整理及今年的立flag产物
电影票务在线售票项目(Vue微信公众号端)
需求:使用Vue重构前端购票页面
技术难点: 1:微信网页登录授权 2:微信JS-SDK ;3:简易版oauth授权认证;
1. 微信网页登录授权
感谢sf社区[Vue微信公众号开发踩坑记录](https://segmentfault.com/a/1190000010753247 的作者提供的在SAP应用上的授权流程思路。
由于项目部署在不同的域上面,架构也不大同意跨域去传输cookie做用户唯一标识,最终采取折中方案为
- 用户访问网站主域名;
- vue客户端(domain)接收请求,在路由解析前判断用户是否登录(比如用户信息,uId是否存在);
- 用户信息不存在,则通过api获取微信授权地址(domain/api/oauthAddress),前端生成一个唯一标识uId并缓存到会话中,同时拼接再跳转到微信服务端授权页面;
- 用户确认授权,微信服务器发起回调请求,这时需要回调到服务器端(domain/api/xxx);
- 服务器端获取用户信息同时与uId建立关联并设置时效性,重定向到Vue客户端(domain);
- 重定向到 Vue客户端,通过uId 去请求(domain/api/getUserInfo)获取用户信息并缓存,进入业务流程
上code
// router.con
import store from '../store/index'
import $http from "../HTTPUtil"
import util from "../util"
router.beforeEach((to, from, next) => {
// 第一次访问 store uId和 userInfo 并不存在,
if (!store.state.userInfo && !store.state.uId) {
// api获取微信授权地址
$http.post("/oauthAddress")
.then(res => {
let data = res.data;
if (data.code === "0") {
const uId = util.uId.getUid()
sotre.commit("setUId", uId) // 生成缓存uId
let urlArr = data.data.split("#")
window.location.replace(urlArr[0] + "@" + uId + "#" + urlArr[1]) // 拼接uId,重定向到微信服务端
}
})
} else if (!store.state.userInfo && store.state.uId) {
// uId存在 ,userInfo不存在
$http.post("/getUserInfo")
.then(res => {
let data = res.data
if (data.code === "0") {
sotre.commit("setUId", '') // 清空uId
sotre.commit("setUserInfo", data.userInfo) // 保存用户信息
next()
}
})
} else if (store.state.userInfo && !store.state.uId) {
// 用户信息存在 ,uId不存在
next()
}
})
存在弊端
- 在一些特殊情况下,前端生成的uId并未能获取到微信用户信息,需要做一定优化处理;
- Java后端重定向Vue前端项目,如果是直接重定向到二级路由的页面domian/#/xxxx/yyyy,部分安卓机会直接白屏,后端无法重定向显示白屏。原因未知
2.微信js-sdk及微信支付
- 由于ios/安卓端存在内核渲染不同,而安卓系统获取的是当前的url地址。ios系统获取签名的url是我们首次进入的地址或者手动刷新的地址(读绿条的时候),在涉及到微信sdk(分享or支付)会无法触发。
由于是纯前端渲染项目,建议使用hash模式,使用微信提供的JSSDK的时候,不用多次签名当前地址。
// app.vue
mouted(){
$wxConfig._init()
}
// $wxConfig._init.js
$http.post('api/wechatSDk', {url:window.location.href.split("#")[0]})
.then(res=>{
let data = res.data;
let config = {
debug : false
};
if(data.code === "0"){
config = Object.assign(config, data, {
jsApiList: [ //需要使用的JS接口列表,所有JS接口列表见附录2
'checkJsApi',
'onMenuShareAppMessage', // 获取“分享给朋友”按钮点击状态及自定义分享内容接口
'onMenuShareTimeline', // 获取“分享到朋友圈”按钮点击状态及自定义分享内容接口
'onMenuShareQQ', // 获取“分享到QQ”按钮点击状态及自定义分享内容接口
'onMenuShareWeibo', // 获取“分享到腾讯微博”按钮点击状态及自定义分享内容接口
'getLocation',
'chooseWXPay',
'openLocation',
'scanQRCode',
......
]
})
$wx.config(config)
}
})
在用到关于支付功能,跳转到待支付页面在路径上拼接?问号
(window.location.href = window.location.origin +/?#/xxx/yyyy)
完美解决ios端支付无法唤起问题, 同时避开微信公众平台后台授权的url地址只能设置5个的问题;
3. 简易版oauth认证
基于业务安全实现的一套加密oauth, 为前开发人员历时遗留问题,在js的3des加密算法上需要注意一下几点;
// DESede/ECB/PKCS5Padding
function des(key, message, encrypt, mode, iv, padding){
...
//pad the message depending on the padding parameter
if (padding == 2) message += " "; //pad the message with spaces
else if (padding == 1) {
if (encrypt) {// 加密需要计算这一步骤,解密不用
temp = 8 - (len % 8);
message += String.fromCharCode(temp, temp, temp, temp, temp, temp, temp, temp);
if (temp === 8) len += 8;
}
} //PKCS7 padding
else if (!padding) message += "\0\0\0\0\0\0\0\0"; //pad the message out with null bytes
....
// result = result.replace(/\0*$/g, "");// 经验教训 不注释这行代码,会出现最后3des 加密后的hash字符串如果左后几位都是0 会被匹配掉,导致后端无法解析3des加密串;
...
}