美文网首页
vue-router 'hash' 模式下微信公众号授权 red

vue-router 'hash' 模式下微信公众号授权 red

作者: 无疆wj | 来源:发表于2021-06-17 15:11 被阅读0次

    1 redirect_uri带有'#'问题

    当然,如果可以的话直接使用history模式即可.

    vue-router默认hash模式下,页面的url都带有#,但微信授权的回调地址不能有#,所以要进行一些处理

    1.1 获取code

    const getCodeParams = {
        redirect_uri: encodeURIComponent(location.href.split('#')[0]),
        appid: "***",
        scope: "snsapi_base",
        state: encodeURIComponent(
          JSON.stringify({
            p: "/login", // 实际的redirect_uri路由path
            ... // 其它参数
        })
      ),
    };
    location.href = `https://open.weixin.qq.com/connect/oauth2/authorize?appid=${getCodeParams.appid}&redirect_uri=${getCodeParams.redirect_uri}&response_type=code&scope=${getCodeParams.scope}&state=${getCodeParams.state}#wechat_redirect`;
    

    1.2 全局路由守卫处理

    授权后微信自动跳转的url:http://***/login?code=***&state=***#/
    处理后的url:http://***/#/login?code=***&state=***

    vue router 4.x代码实现,

    router.beforeEach((to, from) => {
      // console.log(to, from);
      if (replaceWechatRedirectUri()) return false;
    });
    
    /**
     * 处理微信授权回调redirect_uri
     */
    function replaceWechatRedirectUri() {
      const w = location.href.indexOf('?');
      const j = location.href.indexOf('#');
      if (w !== -1 && j > w && getQueryVariable('state')) {
        const state = (getQueryVariable('state') as string).split('#')[0];
        const redirect_path = JSON.parse(decodeURIComponent(state)).p;
        const url =
          location.origin +
          '[多级目录路径]/#' +
          redirect_path +
          `?code=${getQueryVariable('code')}&state=${state}`;
        location.replace(url);
        return true;
      }
    }
    

    注:

    1. [多级目录路径]如果项目不是部署在网站根目录,需要在url上自己加上多级目录的路径
    2. getQueryVariable()是获取url参数的自定义方法

    2 授权后执行后退操作,死循环问题

    页面历史
    pageA -> pageB(在此页面开始授权) -> pageC(微信授权页面) -> pageB?code=***(授权完成后微信重定向)

    2.1 问题描述

    我们在pageB?code=***可以获取到code,然后去换取openid;但是在pageB?code=***执行后退操作的时候,会自动重授权再进入pageB?code=***,再后退亦然,就进入了一个死循环.

    2.2 原因

    微信授权页pageC会push到浏览器的历史记录中,而不是replace的方式

    2.3 解决

    pageB?code=***中把url携带的code参数保存在sessionStorage,然后自动执行执行一次后退操作,返回到pageB,这样既能拿到code又能保持正常的页面历史了

    vue3代码实现

    /**
     * useGetOpenId
     */
    import { ref, Ref } from 'vue';
    import { useRoute } from 'vue-router';
    import { RequestWeChatUserInfo } from '***';
    
    /**
     * 获取用户openid
     */
    interface Result {
      openIdRef: Ref<string>;
    }
    export const useGetOpenId = (): Result => {
      const route = useRoute();
    
      const openIdRef = ref('');
      const urlCode = route.query.code;
      const localCode = sessionStorage.getItem('wxAuthCode');
      const localOpenId = sessionStorage.getItem('wxOpenId');
    
      if (localOpenId) {
        openIdRef.value = localOpenId;
      } else if (urlCode) {
        sessionStorage.setItem('wxAuthCode', urlCode as string);
    
        history.go(-1); // 后退
      } else if (localCode) {
        sessionStorage.removeItem('wxAuthCode');
    
        // 获取openid
        RequestWeChatUserInfo({ code: localCode }).then((res: any) => {
          openIdRef.value = res.data.openid;
          sessionStorage.setItem('wxOpenId', res.data.openid);
        });
      } else {
        // 获取code
        const getCodeParams = {
            redirect_uri: encodeURIComponent(location.href.split('#')[0]),
            appid: '***',
            scope: 'snsapi_base',
            state: encodeURIComponent(
              JSON.stringify({
                p: route.path,
              }),
            ),
          };
          location.href = `https://open.weixin.qq.com/connect/oauth2/authorize?appid=${getCodeParams.appid}&redirect_uri=${getCodeParams.redirect_uri}&response_type=code&scope=${getCodeParams.scope}&state=${getCodeParams.state}#wechat_redirect`;
      }
    
      return { openIdRef };
    };
    
    
    /**
     * pageB
     */
    <template>
      <div class="page" v-if="openIdRef">
        <pre>{{ openIdRef }}</pre>
      </div>
    </template>
    
    <script setup lang="ts">
      import { useGetOpenId } from './hooks/useGetOpenId';
      const { openIdRef } = useGetOpenId();
    </script>
    

    注:

    1. 可以在pageB没获取到openId的时候,隐藏整个页面,这样体验更好一些,没有页面闪烁;
    2. 有个疑问,从pageB?code=***后退到pageB要跨越pageC,明显是2条历史记录,在死循环问题中就已知;
      但是pageB?code=***执行后退的时候只用返回一条记录(history.go(-1))就到了pageB.这个想不明白...

    相关文章

      网友评论

          本文标题:vue-router 'hash' 模式下微信公众号授权 red

          本文链接:https://www.haomeiwen.com/subject/uajcyltx.html