附:微信官方文檔
前言:在用vue做微信公衆號網頁項目的授權登錄中踩過不少坑,在這裏記錄一下。首先在選擇由後端做登陸還是前端傳token登錄的方式上產生了分歧。兩種方式在不同的公司裏都用過,後端做登陸無非是前端跳轉到jsp或者php頁面,後端把登錄做了在跳轉回頁面,這種方式前端方便了,但是中途需要跳轉多次,很影響體驗,所以最終選擇了前端傳token的方法進行登錄。
不想看過程的可以直接往下拉查看完整代碼
目錄
一、授權流程
由微信的官方文檔得知,授權登陸共分爲四步:
其中,第一步由前端來做,第二步前端通過ajax把code傳到後端,後端獲取access_token,第三步第四步則需要後端完成。
寫代碼之前需要明確下需求,整理下思路,先想在寫是個好習慣。
我們需要做的是:
1、前端在需要獲取用戶信息的頁面調起登錄,某些頁面不需要,比如首頁、某些展示靜態頁。
2、微信返回,前端截取返回url中的code傳給後臺,並把後臺返回的token存到session和axios的header頭中。
3、如果session中已經有token了,調另一個接口,判斷token是否已經過期,過期重新登陸。
開始寫代碼。
因爲單頁面應用的url帶着#,微信授權登陸回調對#支持不友好,所以我們把路由換成history模式,後臺配合改一下,不然頁面會404。
mode: "history"
在路由守衛的beforeEach中寫登錄代碼
首先登錄,1:
window.location.href = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=" + appid + "&redirect_uri=" + redirect_uri + "&response_type=code&scope=snsapi_userinfo&state=STATE#wechat_redirect"
白名單判斷:
let noLoginArr = ["/"], isCur = false
for (let i of noLoginArr) {
if (to.path == i) {
isCur = true
}
}
if (isCur) { //白名單內不做登錄判斷,直接next
next()
}
登陸之後截取url中的code傳給後臺,2:
let data = {
code: code
}
axios.post('/api/auth/code', data).then((res) => {
if (res.code == 200) {
sessionStorage.setItem("token", res.data.token)
axios.defaults.headers.common['token'] = res.data.token
next()
} else if (res.code == 401) { //後臺判斷toke是否失效,失效返回401重新授權登陸
//去登錄
window.location.href = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=" + appid + "&redirect_uri=" + redirect_uri + "&response_type=code&scope=snsapi_userinfo&state=STATE#wechat_redirect"
}
}).catch(function (error) {
});
如果session中有token,3:
axios.defaults.headers.common['token'] = sessionStorage.getItem("token")
let data = {
token: token
}
axios.post('/api/auth/checkToken', data).then((res) => { //判斷token是否過期接口
if (res.code == 200) {
next()
} else if (res.code == 401) { //後臺判斷toke是否過期,過期返回401重新授權登陸
sessionStorage.setItem("token","")
axios.defaults.headers.common['token'] = ""
//去登錄
window.location.href = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=" + appid + "&redirect_uri=" + redirect_uri + "&response_type=code&scope=snsapi_userinfo&state=STATE#wechat_redirect"
}
}).catch(function (error) {
});
說一下自己踩得一個坑:登陸之後,在當前頁面不動等token過期,刷新頁面。此時頁面會不停的跳轉
解決方案:每次登錄時,去除回調url中的code和state,所以大家在頁面間傳值的時候不要使用code和state關鍵詞。
二、完整代碼
以下是完整代碼:
const routes =[
// 你的路由
]
const router = new VueRouter({
mode: "history",
routes
})
function delCodeandstate(to) { //函數作用:去除url中的code和state
let path = ""
for (let i in to.query) {
if (i != "code" && i != "state") {
path = path + "&" + i + "=" + to.query[i]
}
}
path = path == "" ? "" : path.substring(1, path.length)
path = path == "" ? "" : "/?" + path
return path;
}
router.beforeEach((to, from, next) => {
let fullPath = to.fullPath
if (to.fullPath.includes("code")) { //判斷url中是否有code,踩坑1-頁面反覆跳轉
fullPath = delCodeandstate(to)
}
let redirect_uri = encodeURIComponent(newUtils.getPath().url + fullPath), appid = newUtils.getPath().appid //1、newUtils.getPath()是寫的公共方法,裏面是url和appid等參數。2、redirect_uri,授權登陸後的回調地址,需要進行encodeURIComponent處理
let code = to.query.code, state = to.query.state
let noLoginArr = ["/"], isCur = false, token = sessionStorage.getItem("token") //noLoginArr,白名單,不需要授權登陸的頁面
for (let i of noLoginArr) {
if (to.path == i) {
isCur = true
}
}
if (isCur) { //白名單內不做登錄判斷,直接next
next()
} else {
if (code && state && !token) { //登陸之後獲取到code,傳到後臺登錄
let data = {
code: code
}
axios.post('/api/auth/code', data).then((res) => {
if (res.code == 200) {
sessionStorage.setItem("token", res.data.token)
axios.defaults.headers.common['token'] = res.data.token
next()
} else if (res.code == 401) { //後臺判斷toke是否失效,失效返回401重新授權登陸
//去登錄
window.location.href = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=" + appid + "&redirect_uri=" + redirect_uri + "&response_type=code&scope=snsapi_userinfo&state=STATE#wechat_redirect"
}
}).catch(function (error) {
});
} else if (token) { //已登錄,有token,判斷是否過期
axios.defaults.headers.common['token'] = sessionStorage.getItem("token")
let data = {
token: token
}
axios.post('/api/auth/checkToken', data).then((res) => { //判斷token是否過期接口
if (res.code == 200) {
next()
} else if (res.code == 401) { //後臺判斷toke是否過期,過期返回401重新授權登陸
sessionStorage.setItem("token","")
axios.defaults.headers.common['token'] = ""
//去登錄
window.location.href = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=" + appid + "&redirect_uri=" + redirect_uri + "&response_type=code&scope=snsapi_userinfo&state=STATE#wechat_redirect"
}
}).catch(function (error) {
});
} else { //未登錄,沒有token,去登錄
//去登錄
window.location.href = "https://open.weixin.qq.com/connect/oauth2/authorize?appid=" + appid + "&redirect_uri=" + redirect_uri + "&response_type=code&scope=snsapi_userinfo&state=STATE#wechat_redirect"
}
}
})
export default router