天天看點

【Electron-Vue】建構桌面應用(42)- 企業微信掃碼登入1.前言2.企業微信掃碼登陸3.問題4. 更正

1.前言

在前面的文章中支援了

釘釘掃碼

方式登入用戶端,然後就可以控制目前登入的使用者通路權限。現在主流的團隊協作方式,一種是

釘釘

,另外一種就是

企業微信

了。

既然支援了

釘釘掃碼的方式

,那就需要支援

企業微信掃碼的方式

2.企業微信掃碼登陸

詳見官方API

仔細看了一下官方提供的API,感覺跟釘釘很像,也有很大的不同之處。兩者的差別如下:

釘釘掃碼分為以下幾步:
  1. 釘釘開發者背景需要配置

    appid

    redirecturi

  2. 通過上面的配置項在建構釘釘掃碼對象的時候,去建構一個連接配接,并且使用encode編碼,同時支援樣式的設定。
  3. 建構完釘釘對象,會去給

    window

    建立一個監聽

    message

    的函數。以便在觸發掃碼授權之後,能通過該callback函數拿到一些相關資訊。比如:

    event.origin

    event.data

    。其中

    origin為釘釘域名https://login.dingtalk.com

    ,而

    data就是臨時授權碼

  4. 臨時授權碼

    發給服務端,服務端根據

    臨時授權碼做重定向拿到真正的code值

    ,然後根據

    code

    去釘釘拿到目前掃碼登陸的使用者。成功後傳回使用者的資訊給前端,用于顯示。由于之前沒有解決重定向的問題,是以重定向交給了背景處理。背景接收到重定向302就直接不管,因為服務端沒有網頁,不需要處理重定向。這是一個取巧的方法。

而企業微信有些差别

企業微信掃碼登陸分為下面幾步:
  1. 企業微信開發者背景配置

    appid

    redirecturi

    以及

    agentid

  2. 通過上面的配置資訊,去建構一個企業微信對象,該對象中不需要建構用于重定向的連接配接。且不支援樣式的配置。如果你想修改樣式,需要自定義樣式檔案,來覆寫掉企業微信預設的樣式。
  3. 根據官方文檔是沒有提及關于監聽

    message

    callback

    函數的的,不知道官方是不是做了處理。如果拿不到callback函數,那麼我就無法擷取到企業微信傳回的資料,也就拿不到

    code

    值。
  4. 如果能拿到code值,将code值傳給服務端,服務端根據code值去企業微信拿到掃碼使用者的資訊,并傳回給前端。

問題出現在第三步。看過企業微信官方的API文檔你就會知道,它沒有關于

message

的callback函數說明。于是,就檢視了一下源碼:

!function(a, b, c) {
	function d(c) {
		var d = b.createElement("iframe"),
		e = "https://open.work.weixin.qq.com/wwopen/sso/qrConnect?appid=" + c.appid + "&agentid=" + c.agentid + "&redirect_uri=" + c.redirect_uri + "&state=" + c.state + "&login_type=jssdk";
		e += c.style ? "&style=" + c.style: "",
		e += c.href ? "&href=" + c.href: "",
		d.src = e,
		d.frameBorder = "0",
		d.allowTransparency = "true",
		d.scrolling = "no",
		d.width = "300px",
		d.height = "400px";
		var f = b.getElementById(c.id);
		f.innerHTML = "",
		f.appendChild(d),
		d.onload = function() {
			d.contentWindow.postMessage && a.addEventListener && (a.addEventListener("message",
			function(b) {
				b.data && b.origin.indexOf("work.weixin.qq.com") > -1 && (a.location.href = b.data)
			}), d.contentWindow.postMessage("ask_usePostMessage", "*"))
		}
	}
	a.WwLogin = d
} (window, document);
           

其實從源碼中可以看出來,它其實是建立了一個frame,然後把企業微信二維碼作為src嵌入到frame中,同時設定了一些樣式。

在最後的函數中可以看出來,他其實也是做了建立關于

message

的監聽事件。

d.contentWindow.postMessage

可能是指,掃碼後發送的消息。

a.addEventListener

是判斷有無監聽函數。

如果上面兩個都為true,那麼就會建立一個監聽函數,并且在監聽函數中拿到

data

origin

資料。

了解這些細節,就可以動手寫代碼了。

2.1 建立企業微信對象

由于在企業微信開發者平台配置的

appid

redirecturi

以及

agentid

都是存在服務端的,是以第一步應該是去服務端擷取這三個值。具體的代碼我就不寫了,就是一個請求的事情。

拿到這個三個值,就可以在點選

企業微信掃碼

跳轉到掃碼頁面上去建構這個掃碼對象了。

由于使用的是

VUE

,可以通過

this.$router.push

的方式将值放到query中,然後在掃碼頁面,通過

this.$route.query

去擷取。

登陸頁面

login.vue

query = {
  loginVo: this.loginVo,
  redirecturi: result.Redurl,
  appid: result.Qrappid,
  agentid: result.Qragentid,
};
this.$router.push({
  path: this.scantype === "dingding" ? "/scan" : "/wechatscan",
  query: query,
});
           

企業微信掃碼

wechatscan.vue

,在created函數中指派操作

created() {
  this.loginVo = this.$route.query.loginVo;
  this.redirecturi = this.$route.query.redirecturi;
  this.appid = this.$route.query.appid;
  this.agentid = this.$route.query.agentid;
},
           

因為建立掃碼對象需要綁定在一個頁面DOM容器上,是以需要等頁面渲染之後,才能建立這個對象,否則在建立對象的時候會出現容器不存在的錯誤資訊。是以,我們需要在

mounted

生命周期函數中去建立這個掃碼對象:

建立掃碼容器:

建立掃碼對象:

mounted() {
// 建立一個企業登陸對象,由于需要渲染挂載到指定的div上,是以需要確定該div已被渲染,否則會出現錯誤
window.WwLogin({
  id: "wechat_container",
  appid: this.appid,
  agentid: this.agentid,
  redirect_uri: encodeURIComponent(this.redirecturi),
});
// 建立掃碼監聽事件,需要在不用的時候進行清除
if (typeof window.addEventListener != "undefined") {
  window.addEventListener("message", this.handleMessage, false);
} else if (typeof window.attachEvent != "undefined") {
  window.attachEvent("onmessage", this.handleMessage);
}
},
           

2.2 建立監聽函數

我們可以列印一下傳回的資料:

handleMessage(event) {
      console.log("event", event);
      let origin = event.origin;
      console.log("event.origin", event.origin);
      if (origin == "https://open.work.weixin.qq.com") {
        console.log("event.data", event.data);
        const query = event.data.split("?")[1];
        const params = qs.parse(query);
        const code = params.code;
        console.log("code", code);
        //擷取到code後就可以發給服務端做驗證

        });
      }
    },
           
【Electron-Vue】建構桌面應用(42)- 企業微信掃碼登入1.前言2.企業微信掃碼登陸3.問題4. 更正

從結果來看我們确實拿到了

event.origin

event.data

了。不過

data

資料我們還需要再處理一下,他給我們做成了一個包含參數的連接配接,我們可以借助于

qs

來轉化一下。

下面的代碼就相對簡單了,我就不再贅述了。

3.問題

3.1 企業微信重定向的問題

上面講到了

釘釘掃碼

企業微信掃碼

的差別:

  1. 釘釘掃碼

    需要先擷取到臨時碼,然後根據臨時碼去擷取授權碼,通過授權碼認證通過後,就會重定向到你所配置的

    redirecturi

  2. 企業微信掃碼

    則直接或擷取到授權碼,掃碼成功後就會進行重定向。
  3. 由于

    釘釘掃碼

    分為兩步,前端則負責取到

    臨時碼

    ,然後服務端根據

    臨時碼

    去擷取到授權碼,然後認證重定向。不需要在前端進行重定向。服務端的處理邏輯是,收到302重定向直接忽視即可,然後将擷取到的

    使用者資訊

    傳回給用戶端。用戶端再進行頁面跳轉即可完成掃碼過程。
  4. 企業微信掃碼

    卻不一樣,因為它拿到的授權碼的過程都是在用戶端,導緻在拿到授權碼後,認證成功後會進行重定向,而重定向操作是在用戶端,重定向到你所配置的

    redirecturi

    。導緻你需要在用戶端做重定向的處理。

那麼問題來了,如何處理

企業微信掃碼

的重定向操作。我們知道浏覽器輸入一個位址或者通過

window.location.href

便可以進行重定向。如果你做過用戶端開發,或者是使用過electron做開發,那麼你肯定會知道,在開發環境下通過

npm run dev

指令,會進入到開發環境,

nodejs

會幫你啟動一個本地服務和對應的端口,比如我的開發環境為

localhost:9080

【Electron-Vue】建構桌面應用(42)- 企業微信掃碼登入1.前言2.企業微信掃碼登陸3.問題4. 更正

而通過開發者模式控制台也可以看到:

【Electron-Vue】建構桌面應用(42)- 企業微信掃碼登入1.前言2.企業微信掃碼登陸3.問題4. 更正

知道這個位址,有的人可能會想到:

如果我得redirecturi配置為lcoalhost:9080,那麼在掃碼之後的重定向不就會重定向到我的頁面了麼?

對,确實如此。但是你别忘了這是在開發環境,你有沒有測試過生産環境呢?

記得在以前的相關文章中也進行過測試,結果是:

跑在本地的服務,是沒有所謂的localhost:9080的。我也曾嘗試能不能通過nodejs去啟動一個服務并且端口為9080,然後去監聽9080端口,收到重定向後再做進一步的處理但很遺憾的是我們不可能為了這個卻占用本地的一個端口,要知道每一個端口都有其意義,而且你也不能保證使用者的這個端口有沒有被其他應用占用。是以,這樣做肯定是不行的。

如果我們配置的位址在不存你或者是其他位址,那麼在進行重定向後,頁面将是一片空白(也就是重定向到一個不存在的頁面),即便這個位址存在,你也需要在本地或者伺服器上托管一套前端代碼。

比如現在,我通過

企業微信掃碼

登陸後,需要跳轉到首頁面system,處理邏輯為:

this.$electron.ipcRenderer.once("window-menu-message", () => {
   this.$router.push('/system')
});
           
【Electron-Vue】建構桌面應用(42)- 企業微信掃碼登入1.前言2.企業微信掃碼登陸3.問題4. 更正

掃碼的結果如下圖,其實可以看到整個掃碼的流程還算順利,直到看到最後一句話

Navigated to chrome-error://chromewebdata/

,知道他是進行了重定向,且重定向失敗了,導緻出現了這個錯誤。

【Electron-Vue】建構桌面應用(42)- 企業微信掃碼登入1.前言2.企業微信掃碼登陸3.問題4. 更正

Navigated to chrome-error://chromewebdata/

由于某種原因,您的代碼試圖導航到無效(不存在)的URL,然後導緻 window.location.href 為 chrome-error:// chromewebdata 。

而在開發者工具network中也可以看到,它确實嘗試進行重定向到我配置的

redirecturi=https://127.0.0.1:8080/wxqcc

,但事實上這個位址是不存在的,是以才會出現上面的那個問題。

【Electron-Vue】建構桌面應用(42)- 企業微信掃碼登入1.前言2.企業微信掃碼登陸3.問題4. 更正

而此時的掃碼之後的

/system

頁面也确實是一片空白。

【Electron-Vue】建構桌面應用(42)- 企業微信掃碼登入1.前言2.企業微信掃碼登陸3.問題4. 更正

既然問題出現了那就需要找到解決辦法。

從可行性來講有兩種處理方式:

  1. 解決重定向,或者禁止浏覽器進行重定向。
  2. 當重定向到一個不存在的頁面時,将其重定向回來,然後通過路由跳轉到

    system

    頁面。

*而在關于

禁止重定向

的方法上,沒有找到合适的處理方式,這個還待研究,暫時TODO一下。

而關于第二種方式重定向之後再次進行重定向,想起來有點靠譜。動手嘗試一下。

~~想法是:

掃碼成功後,通過window.location.href

重定向到

/system

頁面。而關于頁面之間的跳轉其實是通過

vue的$router

實作的,這個不受

location

的限制,如果直接重定向

window.location.href='/system'

this.$electron.ipcRenderer.once("window-menu-message", () => {
  window.location.href = '/system'
});
           

從下圖可以看出,它确實往

/system

中重定向了,但是

/system

路徑不存在。

【Electron-Vue】建構桌面應用(42)- 企業微信掃碼登入1.前言2.企業微信掃碼登陸3.問題4. 更正

vue

中關于路由的配置資訊如下,這裡可以猜出是不是使用的hash路由?

export default new Router({
  routes: [
    {
      path: '/',
      name: 'login',
      component: require('@/pages/login/Login').default
    },
    {
      path: '/system',
      name: 'system',
      component: require('@/pages/home/system/System').default
    },
    {
      path: '/user',
      name: 'user',
      component: require('@/pages/home/user/User').default
    },
    {
      path:'/scan',
      name:'scan',
      component: require('@/pages/home/scan/Scan').default
    },
    {
      path:'/wechatscan',
      name:'wechatScan',
      component: require('@/pages/home/scan/WechatScan').default
    }
  ]
})
           

通過列印一下

window.location.href

,可以看出上面配置的路由資訊,其實在浏覽器中是

/#/system

而不是

/system

【Electron-Vue】建構桌面應用(42)- 企業微信掃碼登入1.前言2.企業微信掃碼登陸3.問題4. 更正

那接着嘗試着使用

window.lcoation.href='/#/system'

,發現依然無法通路,跟上面使用

/system

一樣。

然後嘗試能不能往

/

進行重定向呢?

this.$electron.ipcRenderer.once("window-menu-message", () => {
  window.location.href = '/'
});
           

然後,發現掃碼後,能正常重定向到登入頁,因為登入頁配置的是

'/'

???

如果,能重定向到登入頁,也不是不可以,因為重定向登入頁,也就意味着在我的項目中是可控的,可以将其通過路由

this.$router

的方式跳轉到

/system

頁面。

那麼既然重定向到登入頁,也就意味着我需要做一些特殊的處理:

  1. 重定向到登入頁,意味着渲染了兩次登入頁,那麼你需要根據一個标志位

    isLogined

    來判斷需不需要走登陸的流程。即如果你是通過掃碼進行重定向的,那麼就不需要走登陸流程,而直接跳轉到

    system

    頁面。如果不是,那麼需要做登陸流程。
  2. 由于你是從新走了一遍登陸頁面,那麼你需要将一些狀态值重新修改成正确的。比如我登入後的托盤圖示應該是登入後的狀态即高亮顯示,而未登入(在登入頁)狀态下,應該是灰色的。那麼你重定向到登入頁,勢必會讓圖示從高亮變成灰色的,那麼你就需要重新将圖示修改為高亮。
  3. 在退出或者登出的時候,應該将1中設定的标志位進行重置,否則下次登入,會直接跳轉到

    system

    而不走登入了,程式就會異常。

    具體的代碼其實很簡單,掃碼登陸成功後,通過代碼設定

    isLogined

然後在登入頁的

created

周期函數中處理:

created() {
  if (localStorage.getItem("isLogined") === "true") {
  	// 由于是登陸後重定向到登入頁,是以需要對一些标志做處理
    this.$store.commit("SET_IS_LOGIN", true);
    this.$store.commit("SET_PASSWORD_MSG", false);
    this.$router.push("/system");
    // 使用者成功登陸之後,修改托盤菜單及隐藏表單
    this.$electron.ipcRenderer.send("window-menu", true);
    this.$electron.ipcRenderer.send("system-status", {
      isLogin: true,
      status: true,
    });
  }
}
           

由于,我的應用是,登入後直接隐藏,作為一個認證的工具,不用顯示界面,是以我可以在隐藏之後做處理,使用者是感覺不到賬任何變化的。可能對于不同的需求需要做不同的處理吧。

在驗證一下,确實能夠

正常

使用。隻是總覺得别扭。等研究解決重定向的問題了,再來從根本上解決問題,而不是使用一些取巧的方式。因為,說不定哪天代碼發再度變高了,就會導緻其他的問題。~~

3.2 樣式覆寫的問題

檢視釘釘掃碼的文檔,可以看出來,釘釘在建立掃碼對象的時候,就可以指定其樣式(寬高,背景色…)。

var obj = DDLogin({
     id:"login_container",//這裡需要你在自己的頁面定義一個HTML标簽并設定id,例如<div id="login_container"></div>或<span id="login_container"></span>
     goto: "", //請參考注釋裡的方式
     style: "border:none;background-color:#FFFFFF;",
     width : "365",
     height: "400"
 });
           

企業微信掃碼

就不一樣了,他需要你定義一個css樣式檔案然後通過href屬性去引用這個樣式檔案,并且隻支援

https

var wwLogin = new WwLogin({
        "id": "wx_reg",  
        "appid": "",
        "agentid": "",
        "redirect_uri": "",
        "state": "",
        "href": "",
        "lang": "zh",
});
           

其中

href

使用也有執行個體,就挺懵逼的。我隻想簡單的配置一下樣式

【Electron-Vue】建構桌面應用(42)- 企業微信掃碼登入1.前言2.企業微信掃碼登陸3.問題4. 更正

嘗試在掃碼的同級目錄下建立一個css檔案,然後引入後發現

【Electron-Vue】建構桌面應用(42)- 企業微信掃碼登入1.前言2.企業微信掃碼登陸3.問題4. 更正

從下圖看出,這個位址指向了企業微信開發者位址

https://open.work.weixin.qq.com/wwopen/sso/v1/index.css

【Electron-Vue】建構桌面應用(42)- 企業微信掃碼登入1.前言2.企業微信掃碼登陸3.問題4. 更正

好蒙蔽啊,難道我要上傳自己的樣式檔案到企業微信的伺服器上麼?這也太扯了吧。

從DOM元素中可以看到,原來他是把

./

解析到目前的位址中,即

https://open.work.weixin.qq.com/wwopen/sso/

的同級,是以我們不能在項目中去使用這個樣式檔案,必須要在一個确切的

https

協定的位址才可以。

【Electron-Vue】建構桌面應用(42)- 企業微信掃碼登入1.前言2.企業微信掃碼登陸3.問題4. 更正

我們知道iframe還會牽扯到一個問題,那就是跨域的問題,不同域名之間猶豫同源政策是不支援js跨域修改的。多以想要通過js去操作iframe中的資料幾乎是不可能的。

在網上看到了一個提問,從官方回答來看,是不支援修改樣式檔案的,由于是2020年的問題了,現在的新版本給出了上面的通過

href

去引用連接配接css檔案位址的方式應該是可行的:

【Electron-Vue】建構桌面應用(42)- 企業微信掃碼登入1.前言2.企業微信掃碼登陸3.問題4. 更正

3.3 修改源碼調整樣式

由于提供https來承載一個css檔案的開銷較大,得不償失。是以打算放棄上面的方式(當然如果你的面闆足夠大,那麼就不需要關心這些,隻要使用企業微信預設的樣式就好了,企業微信的預設寬300px,高400px)。

那麼如果我得程式面闆大小是固定的,或者不足以顯示企業微信預設的大小,就會顯示出滾動條,類似下面的。

【Electron-Vue】建構桌面應用(42)- 企業微信掃碼登入1.前言2.企業微信掃碼登陸3.問題4. 更正

前面我們也知道同源政策導緻我們無法去直接修改企業微信的iframe中樣式,即便是擷取資料也不行。那麼我們能想到最直接的辦法就是:

将企業微信的掃碼源碼拉取到本地,然後在源碼上動手腳,這樣一來iframe就是完全可控的了,接下愛我們就是可以在源碼上動手腳了

什麼?你不知道則呢麼拉取源碼?

直接點選企業微信官方提供的js檔案,就會在浏覽器中顯示出來他的源碼,然後将源碼copy出來粘貼到你的項目中。

為了友善,我是直接放到首頁面中的。在我的

Electron-vue

項目中,首頁面是

index.ejs

模闆檔案,當然如果你是用的是其他架構,可以放到你的主入口檔案中。

【Electron-Vue】建構桌面應用(42)- 企業微信掃碼登入1.前言2.企業微信掃碼登陸3.問題4. 更正

試想啊,如果你想讓企業微信掃碼的iframe适應你的面闆大小,那麼你得給他設定一個寬高吧,當然在源碼中你可以看到代碼是可以直接設定寬高的,從掃碼的顯示來看:

寬度夠用,而高度不足,這樣就可以設定寬度100%(設定100%會讓二維碼自動居中,雖然我們沒做居中處理,猜想是二維碼内部做了處理),高度設定為你得面闆高度,比如我的是315px,那麼當我去設定的時候,就會發現,企業微信的掃碼被裁減了,剩餘的不顯示了

,如下:

【Electron-Vue】建構桌面應用(42)- 企業微信掃碼登入1.前言2.企業微信掃碼登陸3.問題4. 更正

會發現,它的掃碼提示被裁剪了…。

原因猜想應該是:

iframe的大小不足以容納二維碼的大小,且無法去通過樣式和js去控制二維碼圖檔的寬高,iframe變小了,二維碼沒變,導緻二維碼被裁剪了

雖然被裁減了,但是好像大小合适,也能正常掃碼用了。

想要調試iframe的樣式,首先我們要找到這個iframe,檢視了一下iframe的屬性發現并沒有什麼好的方法去定位這個iframe,不得已我們隻能通過id去擷取它:

【Electron-Vue】建構桌面應用(42)- 企業微信掃碼登入1.前言2.企業微信掃碼登陸3.問題4. 更正

既然要使用到id那麼就需要給iframe綁定一個id,如下綁定了一個叫做

wxiframe

的:

!function(a, b, c) {
   function d(c) {
     var d = b.createElement("iframe"),
     e = "https://open.work.weixin.qq.com/wwopen/sso/qrConnect?appid=" + c.appid + "&agentid=" + c.agentid + "&redirect_uri=" + c.redirect_uri + "&state=" + c.state + "&login_type=jssdk";
     e += c.style ? "&style=" + c.style: "",
     e += c.href ? "&href=" + c.href: "",
     d.src = e,
     d.frameBorder = "0",
     d.allowTransparency = "true",
     d.scrolling = "no",
     d.width = "100%",
     d.height = "315px",
     d.id = 'wxiframe';
     var f = b.getElementById(c.id);
     f.innerHTML = "",
     f.appendChild(d),
     d.onload = function() {
       d.contentWindow.postMessage && a.addEventListener && (a.addEventListener("message",
       function(b) {
         b.data && b.origin.indexOf("work.weixin.qq.com") > -1 && (a.location.href = b.data)
       }), d.contentWindow.postMessage("ask_usePostMessage", "*"))
     }
   }
   a.WwLogin = d
 } (window, document);
           

綁定之後,我們可以使用通過

getelementbyid

擷取到iframe,如果你懂css的話可能會想到

transform

屬性,通過它來縮放大小。

!function(a, b, c) {
   function d(c) {
     var d = b.createElement("iframe"),
     e = "https://open.work.weixin.qq.com/wwopen/sso/qrConnect?appid=" + c.appid + "&agentid=" + c.agentid + "&redirect_uri=" + c.redirect_uri + "&state=" + c.state + "&login_type=jssdk";
     e += c.style ? "&style=" + c.style: "",
     e += c.href ? "&href=" + c.href: "",
     d.src = e,
     d.frameBorder = "0",
     d.allowTransparency = "true",
     d.scrolling = "no",
     d.width = "100%",
     d.height = "315px",
     d.id = 'wxiframe';
     var f = b.getElementById(c.id);
     f.innerHTML = "",
     f.appendChild(d),
     d.onload = function() {
       d.contentWindow.postMessage && a.addEventListener && (a.addEventListener("message",
       function(b) {
         b.data && b.origin.indexOf("work.weixin.qq.com") > -1 && (a.location.href = b.data)
       }), d.contentWindow.postMessage("ask_usePostMessage", "*"))
       var wxiframe = document.getElementById('wxiframe')
       wxiframe.style.transform = 'scale(.9)'
     }
   }
   a.WwLogin = d
 } (window, document);
           

發現,确實變小了,但是掃碼的提示資訊似乎還不顯示。

【Electron-Vue】建構桌面應用(42)- 企業微信掃碼登入1.前言2.企業微信掃碼登陸3.問題4. 更正

通過控制台可以發現,其實你對iframe進行縮放隻是整體縮放了大小,并沒有改變掃碼和iframe的相對位置和大小,這就導緻還是被裁剪的二維碼。是以我們就需要對這個樣式進行設定,當然不一定是圖中的這個樣式,隻要掃碼的任意父節點進行縮放都可以達到效果。

【Electron-Vue】建構桌面應用(42)- 企業微信掃碼登入1.前言2.企業微信掃碼登陸3.問題4. 更正

但是看起來邊距什麼的都需要調整,可能搞起來很麻煩。故我就在這裡做嘗試了(可以嘗試使用jQuery來處理這種),即便不顯示下面的掃碼提示資訊,也依舊能夠掃碼登陸。

3.3 改變窗體大小來适應企業微信掃碼

這個搞起來不難,就是需要中轉幾步:

  1. 點選掃碼的時候,可以通過渲染程序給主程序發送一個消息,主程序收到消息去改變窗體的大小以适應二維碼的大小。
  2. 改變之後再去拉取二維碼顯示。
  3. 進行後續掃碼流程

當然,類似的你還可以建立一個子視窗(可以固定大小和二維碼的大小一緻)來展示二維碼,掃碼之後,銷毀子視窗,将成功的資訊傳給父視窗,那麼父視窗接到子視窗的資料就可以進行跳轉處理了(登陸成功跳轉到首頁面,登陸不成功不跳轉,提示失敗)。

這麼做估計連上面的

重定向問題

也一并解決了。因為子視窗就負責展示二維碼,掃碼流程,隻要擷取到服務端的認證結果,至于子視窗重定向與否,都無關緊要了。因為拿到結果就直接銷毀子視窗了,父視窗就不需要處理重定向了。我覺得應該是這麼回事,雖然沒有嘗試,如果有感興趣的可以告訴我結果。缺點就是,你需要額外定義一個單獨的頁面去支援二維碼,因為牽扯到你需要通過

window.opner

來進行父子視窗的傳參。

4. 更正

在3中提到如何處理重定向的問題,其中提到了兩種解決方案:

  1. 解決重定向的問題
  2. 重定向之後,再利用

    window.location.href='/'

    重定向回項目的根路徑,再通過路由的方式去跳轉到首頁面。

在2的基礎上,今天打包之後,跑在生成環境,發現依然出現空白,也就是說重定向失敗,還是回到了最初。原因是:

通過location進行重定向到/根據路也是基于你起的服務的根路徑

,這就導緻在生成環境沒有所謂的本地服務導緻無法重定向到正确的位址。

看來又回到怎麼去解決

重定向的問題

想了想,由于重定向到一個不存在的位址導緻我的程式無法做後續操作,才會出現空白而無法應對的情況。那麼如果我能夠控制重定向或者監聽到重定向的操作呢?

無獨有偶,在

github

上看到了關于掃碼的

issue

詳見這裡

提到了關于通過

will-navigate

來監聽重定向的操作,其中在官方文檔中也寫道:

【Electron-Vue】建構桌面應用(42)- 企業微信掃碼登入1.前言2.企業微信掃碼登陸3.問題4. 更正

那麼通過這個事件來擷取一下重定向的事件,我們知道在整個掃碼操作中有兩個

navigate

,一個是往企業微信跳轉的時候,另一個就是掃碼成功後企業微信重定向到我們的

redirecturi

上。

那我們隻需要在監聽到重定向操作時,判斷傳回的url是不是我們配置的

redirecturi

就行了,隻要能拿到這個uri,無論是不是真實存在的位址,我們的程式都變得可控了。拿到之後主程序可以向渲染程序中發送一個事件,渲染程序監聽後,通過路由跳轉到

/system

頁面。

主程序中:

// 建立視窗的時候啟動重定向的監聽
 mainWindow.webContents.on('will-navigate', (e, url, status) => {
 	// 此處,redirecturi為了達到可配置的目的,是存伺服器上的,點選掃碼時從服務端擷取到。當然為了友善你也可以寫死,但不建議這麼做。
   if (url.startsWith(redirecturi)) {
     e.preventDefault()
     // do something
     mainWindow.webContents.send('redirect-uri')
   }
 });
           

渲染程序中收到重定向的請求:

// 監聽進行重定向操作,通過路由跳轉到wechatscan首頁面,因為掃碼後他會首先進行重定向,當你重定向到是目前掃碼頁面的時候,才能接收到掃碼的response,否則擷取不到傳回值。傳回到掃碼頁面後,你需要根據傳回值是否掃碼成功,來判斷是否往system跳轉,而不是直接跳轉到system頁面。
this.$electron.ipcRenderer.once("redirect-uri", (event) => {
  this.$router.push('/wechatscan') 
});
           

其中,監聽到重定向的位址為:

[2021-08-12 18:14:21.058] [info] 掃碼登陸參數: {"type":"login","address":"192.168.0.55","port":"10000","username":"zAnkQLjc2Jdp2UVwsex2FDP7p2O-OaBMp-85lvTt2Lc","auth":"wechat"}
[2021-08-12 18:14:21.067] [info] **************url************* https://127.0.0.1:8080/wxqcc?code=zAnkQLjc2Jdp2UVwsex2FDP7p2O-OaBMp-85lvTt2Lc&state=undefined&appid=ww721d49a381861f97
[2021-08-12 18:14:21.891] [info] 掃碼登陸結果: {
  msg: '登入成功',
  pwdinit: 'false',
  time: '2021-08-12 18:14:21',
  type: '0',
  username: '不醉怎能入睡'
}
           

而服務端配置的

redirecturi

為:

https://127.0.0.1:8080/wxqcc

,那麼隻要url中包含

https://127.0.0.1:8080/wxqcc

就可以處理接下來的流程了

繼續閱讀