vue 微信授權解決方案

乖摸摸頭發表於2019-02-16

背景

vue前後端分離開發微信授權
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我在從本地拿引數解析,這個方法應該也是可行的,下次嘗試後更新

相關文章