背景
前后端分離項目 — SpringSocial 綁定與解綁社交賬號如微信、QQ
2018-08-14更新
時隔四個月第一次更新,因為項目重構有一次接觸到了微信授權,思路已經比原來清晰的多了,將重新修改一下整個文章
場景
app將商品分享到微信朋友圈或者分享給微信好友,用戶點擊頁面時進行微信授權登陸,獲取用戶信息。
問題:沒有固定的h5應用首頁,回調不能到index。授權后重定向url帶參數並且很長
本人愚鈍,開發過程中,嘗試過很多方法,踩坑不足以形容我的心情,可以說每一次都是一次跳井的體驗啊。
1.一開始嘗試的方式是前端請求微信連接,返回code,然后code作為再去請求后台接口獲取token,后面看到別人的博客說這個方法不好,最好就是直接請求后台接口,然后后台返回url做跳轉,所以就采用了最傳統的方法,后台返回url,前台跳轉。
2.這個時候就出現一個問題,微信授權要跳跳跳,最終想回到第一次點進來時候的鏈接就蛋疼了,從網上查了一下解決方法,將鏈接本身作為redirect_uri參數,大概就是這個樣子
https://open.weixin.qq.com/connect/oauth2/authorizeappid=xxxxxxxxxxxxxxxxxx&redirect_uri=*www.admin?http://www.xxx.com/h5/product*&response_type=code&scope=snsapi_userinfo&state=STATE&connect_redirect=1#wechat_redirect
然而我們的前台鏈接是這個鬼樣子的,本身帶參數,而且超長,what?微信可能不會接受我長這么丑。/(ㄒoㄒ)/~~
http://www.xxx.com/h5/product?id=6RedfM5O4xeyl0AmOwmyipkHr8AQCv-hYXZVAIFTwDXOsWSKqgu3VaCmaKSerBnacvWuzO3Zwdf8y%2F2K2lvqkluV6Ane4LCAKyPU2tPAPj%2FMF6F6xkzp27GqqpNya7HbdEA34qGQJvHIA9tlIMkeEWid1112b8oZuP3FQBwU%2F%2FMaSrovzQP6LlzWamyPnv0vMizu8uh0ItpJOQUV1m%2FtemF3U9KuHo8rXCw%3D
最終放棄了這個方案
3.考慮如何重定向我的前台地址,並且獲取token
接下來就是我現在用的方法,bug還有很多,先分享一下我的方法,后期優化或有更好的方法再做修改
在main.js中路由全局鈎子判斷本地是不是有user_token,也就是微信授權后返回的token,如果沒有token,並且當前的路由不是author(專門為了授權而生的頁面),那就保存當前的url,比如www.xxx.com/h5/product?id=6RedfM5O4xeyl0AmOwm,然后進入author。那如果本地有token,就是用戶之前授權拿到過token並且vuex里沒有用戶信息,那我就獲取用戶信息並保存在vuex中,這里遇到一個問題就是token會出現過期的情況,那我就刪除了本地的user_token,window.localStorage.removeItem("user_token");刷新頁面 router.go(0);這個時候就重新走了一遍如果沒有token的情況。
第一版方法
router.beforeEach((to, from, next) => {
// 第一次進入項目
let token = window.localStorage.getItem("user_token");
if (!token && to.path != "/author") {
window.localStorage.setItem("beforeLoginUrl", to.fullPath); // 保存用戶進入的url
next("/author");
return false;
} else if (token && !store.getters.userInfo) {
//獲取用戶信息接口
store
.dispatch("GetUserInfo", {
user_token: token
})
.catch(err => {
window.localStorage.removeItem("user_token");
router.go(0);
return false;
});
}
next();
});
2018-08-14第二版方法
不同的地方是將跳轉判斷從author.vue里拿出來放這里了邏輯其實很簡單,有token獲取信息,沒token跳轉授權
router.beforeEach((to, from, next) => {
const token = window.localStorage.getItem('user_token')
if (token) {
if (to.path === '/author') {
next({
path: '/'
})
} else {
store
.dispatch('GetUserInfo', {
user_token: token
})
.then(res => {
// 拉取用戶信息
next()
})
}
} else {
if (to.path !== '/author') {
// 保存用戶進入的url
if (to.path === '/shop' || to.path === '/product') {
window.localStorage.setItem('authUrl', to.fullPath) // 保存用戶進入的url
}
store.dispatch('GetAuthUrl').then(res => {
// 此處返回的是后台拼接的微信授權地址,前台也是可以拼接的,跳轉到微信授權
window.location.href = res.data.url //https://open.weixin.qq.com/connect/oauth2/authorize?appid=aaaaa&redirect_uri=后端java或php地址&response_type=code&scope=snsapi_userinfo&state=STATE&connect_redirect=1#wechat_redirect
})
} else {
next()
}
}
})
下面就是進入author.vue的邏輯,第一次進入author, www.xxxx.com/h5/author,判斷鏈接有沒有token參數,如果沒有就跳微信授權,然后后台會重定向回來並攜帶token,如: www.xxxx.com/h5/author?token=xxxxxxxxx&msg=200
第一版
<template>
<div>
授權中。。。
</div>
</template>
<script>
import {
getWxAuth
} from '@/service/getData'
import {
GetQueryString
} from '@/utils/mixin';
export default {
data() {
return {
token: '',
};
},
computed: {
},
created() {
this.token = window.localStorage.getItem("user_token");
//判斷當前的url有沒有token參數,如果不存在那就跳轉到微信授權的url
//就是前面說的ReturnGetCodeUrl方法
if (!GetQueryString("token")) {
this.ReturnGetCodeUrl();
} else {
//如果有token,如http://www.xxxx.com/h5/author?token=xxxxxxxxx&msg=200,這里的參數就是后台重定向到前台http://www.xxxx.com/h5/author,並攜帶的參數。這樣就可以拿到我們想要的token了
//判斷一下后台返回的狀態碼msg,因為可能出現微信拿不到token的情況
let msg = GetQueryString("msg")
if (msg = 200) {
this.token = GetQueryString("token");
//存儲token到本地
window.localStorage.setItem("user_token", this.token);
//獲取beforeLoginUrl,我們的前端頁面
let url = window.localStorage.getItem("beforeLoginUrl");
//跳轉
this.$router.push(url);
//刪除本地beforeLoginUrl
removeLocalStorage("beforeLoginUrl");
}else{
//msg不是200的情況,可能跳到404的錯誤頁面
}
}
},
methods: {
async ReturnGetCodeUrl() {
let {
data
} = await getWxAuth({});
if (data.status == 200) {
window.location.href = data.url;
}
},
},
watch: {},
components: {},
mounted: function () {}
}
</script>
<style lang='scss' scoped>
</style>
GetQueryString方法
mixin.js
export const GetQueryString = name => {
var url = new RegExp("(^|&)" + name + "=([^&]*)(&|$)");
var newUrl = window.location.search.substr(1).match(url);
if (newUrl != null) {
return unescape(newUrl[2]);
} else {
return false;
}
};
第二版
只用來后台拿到參數返回到author頁面后的攜帶的參數如果獲取成功則跳轉到授權之前保存的url如果失敗提示用戶關閉網頁重新授權,另外有一點值得注意,微信名里有特殊字符的需要轉碼要不授權會失敗
<!-- author -->
<template>
<div>
授權中。。。
</div>
</template>
<script>
import {
mapGetters
} from 'vuex'
import {
Toast
} from 'mint-ui'
import {
GetQueryString,
setLocalStorage,
getLocalStorage,
removeLocalStorage
} from '@/utils'
export default {
data() {
return {
token: ''
}
},
computed: {
...mapGetters([
'userInfo'
])
},
created() {
const wxtoken = GetQueryString('token')
const code = GetQueryString('msg')
if (wxtoken && Number(code) === 200) {
setLocalStorage('user_token', wxtoken)
const historyUrl = getLocalStorage('authUrl')
this.$router.replace(historyUrl)
// removeLocalStorage('authUrl')
} else {
// 沒有拿到后台訪問微信返回的token
Toast('授權失敗請關閉網頁重新進入')
removeLocalStorage('share_token')
removeLocalStorage('authUrl')
}
}
}
</script>
<style lang='scss' scoped>
</style>
整個過程是可以實現授權,但是覺得代碼寫得不好,以后的開發中希望能夠有更優的方法。希望能和大家交流學習。
2018-08-14更新,總結一下,第二次開發流程做了簡化,但是整個思路還是一樣,我之前想到過另外一種方法,是將我的那串長參數先保存在本地,然后去授權的時候就可以讓后台幫我跳轉到固定頁面如/product我在從本地拿參數解析,這個方法應該也是可行的,下次嘗試后更新