業務需求:
使用Vue+vux開發微信公衆號頁面需要微信授權登錄,再通過後臺換取openId,公衆號頁面中有些頁面不需要登錄,有些頁面不需要登錄,在用戶從普通頁面訪問需登錄頁面時,自動跳轉至登錄頁面,授權後繼續登錄前的操作;
解決方案
*前提:微信開發環境、後端配置均已完成
解決思路
- 在main.js中添加路由守衛,路由跳轉時檢測是否已登錄,已登錄則通過,未登錄則拉起微信登錄並記錄當前要訪問的頁面和參數,存放到localStorage中;
- 把根路徑映射到微信登錄成功後要跳轉的頁面,接收code;
- 登錄頁面接收到code後,轉發給自己的後臺服務器,讓它換取openId和token
- 把後臺返回的openid和token存起來,把登錄前的操作從localStorage取出來,繼續跳轉;
解決問題
前端代碼------------------------------->>>>
const ServerAPI = {
host: "https://www.abc.com", //外網可訪問的域名
port: 80, //外網可訪問端口
name: "webapp",//後臺導出war包到Tomcat webapp目錄下的app名
imgRoot: 'static',//後臺圖片存放根目錄
hostPort: function () {
// return this.host + ":" + this.port;
return this.host
}
};
const API = {
APP_LIST: "xxx/xxxxxx",
G_APP_DETAIL: "xxx/xxxxxxxxx",
G_OPEN_ID:"xxx/xxxx",
CREATE_ORDER:"xx/xxxx",
CREATE_PRE_ORDER:"xxx/xxxx",
};
//組裝訪問後臺API的封裝
const assembleAPI = function (api, ...params) {
let url = ServerAPI.hostPort();
if (ServerAPI.name.length >= 1) {
url = url + "/" + ServerAPI.name;
}
url = url + "/" + api;
if (params.length > 0) {
for (let i = 0; i < params.length; i++) {
let p = params[i];
if (i === 0) {
url = url + "?" + p.n + "=" + p.v;
} else {
url = url + "&" + p.n + "=" + p.v;
}
}
}
return url;
};
const assembleImageAPI = function (imageUri) {
return ServerAPI.hostPort() + "/" + imageUri;
};
const assembleImageAPIFromServer = function (imageUri) {
let url = ServerAPI.hostPort();
if (ServerAPI.name.length >= 1) {
url = url + "/" + ServerAPI.name;
}
if (ServerAPI.imgRoot.length >= 1) {
url = url + "/" + ServerAPI.imgRoot;
}
return url + "/" + imageUri;
};
export default {
API,
assembleAPI,
assembleImageAPI,
assembleImageAPIFromServer
}
- 路由配置如下:
routes: [
{
path: '/',
name: 'login',
component: Login,
meta: {
title: "授權跳轉中...",
keepAlive: true,
refreshPage: false,
skipAuth: true,//跳過驗證
}
}, {
path: '/home',
name: 'home',
component: Home,
meta: {
title: "產品列表",
keepAlive: true,
refreshPage: false,
skipAuth: true,
}
},
//...省略
]
* 爲什麼要把根路徑映射到登錄頁面:微信獲取code回調到指定地址,如果映射到其他地址會導致微信回調時地址錯誤等問題 暫時沒有找到其他解決辦法;
- 路由守衛配置:攔截頁面路由跳轉 main.js
/* eslint-disable no-new */
new Vue({
el: '#app',
router,
store,
components: {App},
template: '<App/>'
});
//註冊VUX組件
Vue.component('x-header', XHeader);
Vue.component('tabbar', Tabbar);
Vue.component('tabbar-item', TabbarItem);
let that = this;
router.beforeEach((to, from, , next) => {
//提高用戶體驗 減少卡頓 每個頁面進入時均彈出加載提示
utils.LoadingDialogUtil.showLoading(store, '數據加載中...');
store.commit('referRouterStatus', {to: to});
if (!WXManager.Configure.NEED_AUTH) {//調試頁面時用 可忽略
next();
return;
}
const token = localStorage.getItem(const_key.KEY.TOKEN);
let openid = router.app.$store.state.user.openid;
//這裏只檢查openid
if (!openid) {
if (to.meta.hasOwnProperty('skipAuth') && to.meta.skipAuth) {
next();
} else {
//當前頁url與參數放入緩存
let tempRouter = {to: to.name, from: from.path, params: to.params};
//把操作信息格式化成json字符串存到localStorage
localStorage.setItem(const_key.KEY.TEMP_ROUTER, JSON.stringify(tempRouter));
let authUrl = WXManager.g_codeUrl();
//重定向至授權地址
window.location.href = authUrl;
}
} else {
next()
}
});
* 這裏經過多次嘗試發現: 不能把要訪問的路由信息存放帶store中,微信獲取code成功回調後store存的路由信息會丟失,不知道爲啥;
- 獲取openid組件 Login.vue(只貼script代碼):
import ServerAPI from "../common/ServerAPI";
import utils from "../common/utils";
import CONST_KEY from "../common/CONST_KEY";
export default {
name: "Login",
components: {},
data() {
return {
msg: "正在獲取code"
}
},
created() {
utils.LoadingDialogUtil.hideLoading(this.$store);
const code = this.getUrlParams('code'); // 截取code
const uri = localStorage.getItem("now_url");
if (code) {
//帶有code
let h = window.location.href;
let hArr = h.split('?');
let url = hArr[0];
url = url + '#' + uri;
this.msg = "正在請求微信授權...";
//獲取用戶信息
let openIdUrl = ServerAPI.assembleAPI(ServerAPI.API.G_OPEN_ID, {n: "code", v: code}, {n: "state", v: "y"});
this.axios.get(openIdUrl).then(response => {
let res = response.data;
if (res.status === 200) {let user = res.data;
localStorage.setItem(CONST_KEY.KEY.OPEN_ID, user.openid);
this.$store.state.user.openid = user.openid;
this.msg = "登錄成功,正在爲您定向到目標頁面...";
let tempRouter = localStorage.getItem(CONST_KEY.KEY.TEMP_ROUTER);
tempRouter = JSON.parse(tempRouter);
//登錄成功均跳轉到首頁
// this.$router.push({name: 'home'});
//跳轉至原頁面
this.$router.push({name: tempRouter.to, params: tempRouter.params});
} else {
this.msg = res.msg;
}
}).catch(err => {
console.error(err);
})
} else {
this.msg = "獲取微信授權失敗";
this.$router.push({name: 'home'})
}
}