真高效!實現不同環境下賬號一鍵登錄

前言

在我們的工作過程中,每當需要排查問題、跑冒煙用例、看測試環境的效果時,經常需要在瀏覽器環境中切換登錄賬號,另外,在開發的過程中,也需要在編輯器 VS Code 裏切換代理登錄的賬號。

以政採雲的業務開發爲例:訪問測試、預發等不同環境要切賬號,切換不同角色身份、不同地理區劃、甚至查看有特殊數據時也要切賬號…… 這讓我們的工作中充斥了大量的輸入賬號密碼的無效時間,也需要我們額外維護賬號文檔,非常苦惱。

關於在 VS Code 編輯器裏快捷切換賬號的工具,我們已經有同學設計開發過,在後續的文章中會向大家展示。

本文將講述一下如何在瀏覽器環境,擴展 Chrome 瀏覽器原有的 “記住密碼” 功能,實現快捷登錄、隔離賬號信息以及備註標籤等方便使用的功能,同時分享給測試、後端、產品等其他的夥伴,提高大家的效率,希望這次探索能給更多的人帶來啓發。

需求分析

最終效果預覽

主要演示一下插件的位置,其中,刪除和置頂是常見功能,就不在這裏演示了

一鍵登錄

賬號錄入

Tag 標記和搜索

彈層裏的傳送門

傳送門編寫在 popup/index.html 目錄下,用於提供快捷進入不同環境登錄頁的入口,用顏色清晰地區別開測試、預發等環境,以及記錄輔助系統魯班的地址。

前期設計

Chrome 擴展程序

既然是代替用戶進行瀏覽器頁面的登錄,我們當然可以選擇 Chrome Extension (擴展程序)(https://developer.chrome.com/docs/extensions/) 來解決這一難題。

擴展是基於 Web 技術構建的,例如 HTML、JavaScript 和 CSS。它們在單獨的沙盒執行環境中運行,並與 Chrome 瀏覽器交互。

擴展允許您通過使用 API 修改瀏覽器行爲和訪問 Web 內容來 “擴展” 瀏覽器。

Chrome 瀏覽器將會識別包含 manifest.json 文件的目錄爲擴展文件,所以我們可以開發一個 Chrome Extension 項目來解決這一問題。

前端技術棧

本次 Chrome 插件選用 React 框架開發,其他開發者也可以根據自己的偏好進行技術選型。

第一版本的插件能力暫時不接入後端,數據都存在本地。

美觀的 UI 選型

由於原政採雲登錄頁面是用內部基於 AntD 開發的組件庫,爲了保持視覺風格的統一,我選擇了繼續使用我們內部的組件庫,每個團隊也可以根據自己情況選擇自己的組件庫,或者開源的組件庫,如 ant design,element ui 等。

更便捷的交互設計

既然可以訪問 Web 內容,那麼最簡便的操作就是不用觸發任何其他的按鈕打開彈層,直接 識別登錄頁面,在原有登錄頁面的空白處中 插入我們的組件 DOM 元素,就可以實現最便捷的操作。我們得到一個登錄賬號列表,不必透出密碼,根據我們自己打的標籤判斷當前需要登錄的賬號,一鍵登錄,代替手動操作。

項目搭建

我們建一個空項目,配置必要的 .babelrc 、.gitignore、webpack.config.js 文件,使得文件可以支持 Babel、Git、Webpack 的正常使用,安裝 Less 以及相關的 loader 方便我們的開發,目錄結構大致如下:

目錄結構

 .
 ├── README.md 
 ├── package-lock.json
 ├── package.json
 ├── src
 │   ├── assets # 存放擴展程序的標誌圖片
 │   ├── contentScript # 對 Web 文件的操作
 │   ├── manifest.json # Chrome Extension 的清單文件
 │   └── popup # 用於存放彈出層
 └── webpack.config.js

清單文件 manifest.json

這裏是用來配置擴展程序的基礎信息的文件

 {
   "name""Account Saver",
   "description" : "zcy 賬號管理小精靈~", 
   "version""1.0", 
   "manifest_version": 2, 
   "icons"{ 
     "16""./assets/icon.png", 
     "48""./assets/icon.png",
     "96""./assets/icon.png",
     "128""./assets/icon.png"
 },
   "browser_action"{
     "default_icon""./assets/icon.png", // 插件加載在瀏覽器右上角時的圖標
     "default_title""賬號管理小精靈~", // hover 圖標的提示文字
     "default_popup":"/popup.html" // 默認點擊圖標時彈出的浮層
   },
   "permissions"[
     "tabs",
     "activeTab",
     "storage",
     "notifications"
   ],
   "background"{
     "persistent": false,
     "scripts"["./background.js"]
   },
   "content_security_policy""script-src 'self' 'unsafe-eval'; object-src 'self'",
   "content_scripts"[
     {
         "matches"[
             "http://*/*",
             "https://*/*"
         ],
         "js"[ // content script 文件
           "/popupListener.js"
         ],
         "run_at""document_idle"
     }
 ]
 }

webpack.config.js

如下代碼配置 webpack ,可以幫助我們編譯打包 HTML、JavaScript 和 Less 編寫的樣式文件,打包靜態資源,執行npm run build 獲得打包好的 dist 文件,就可以分享到團隊中了。

 const path = require('path');
 const webpack = require('webpack');
 const CopyWebpackPlugin = require('copy-webpack-plugin');
 const CleanWebpackPlugin = require('clean-webpack-plugin');
 
 const HtmlWebpackPlugin = require('html-webpack-plugin');

 module.exports = {
   mode: 'development',
   context: path.resolve(__dirname, './src'),
   entry: {
     popup: './popup/index.js',
     background: './background/index.js',
     popupListener: './contentScript/popupListener.js',
   },
   output: {
     path: path.resolve(__dirname, './dist'),
     publicPath: '/',
     filename: '[name].js',
   },
   module: {
     rules: [
       {
         test: /\.css$/,
         use: ['style-loader''css-loader'],
       },
       {
         test: /\.less$/,
         use: [
           'style-loader',
           'css-loader',
           'less-loader'],
       },
       {
         test: /\.(js|jsx)$/,
         exclude: /node_modules/,
         use: {
           loader: 'babel-loader',
           options: {
             babelrc: false,
             presets: [
               // 添加 preset-react 識別 react 代碼 
               require.resolve('@babel/preset-react'),
               require.resolve('@babel/preset-env'),
               {
                 plugins: ['@babel/plugin-proposal-class-properties'],
               },
             ],
             cacheDirectory: true,
           },
         },
       },
     ],
   },
   plugins: [
     new HtmlWebpackPlugin({
       title: 'popup',
       template: './popup/index.html',
       inject: true,
       chunks: ['popup'],
       filename: 'popup.html',
     }),
     new webpack.HotModuleReplacementPlugin(),
     new CleanWebpackPlugin(['./dist/''./zip/']),
     new CopyWebpackPlugin([
       { from: 'assets', to: 'assets' },
       { from: 'manifest.json', to: 'manifest.json', flatten: true },
     ]),
   ],
 };

核心代碼

Content Script

Content Scripts 是運行在 Web 頁面的上下文的 JavaScript 文件。通過標準的 DOM,Content Scripts 可以操作(讀取並修改)瀏覽器當前訪問的 Web 頁面的內容,並將信息傳遞給父擴展。

插入浮層

在此我們通過原生 JavaScript 的 createElement()append() 方法向 body 中追加元素,插入浮層。

 const { domain } = document;
 const isZcy = domain.indexOf('zcy') !== -1;
 const userDom = document.getElementsByName('username')[0];

 if (isZcy && userDom) {
   // 域名爲政採雲域名,且存在 name = username 的元素(輸入框)時,在頁面左側插入一個浮層
   const body = document.getElementsByTagName('body')[0];
   const panelWrapper = document.createElement('div');

   ReactDOM.render(<AccountPanel />, panelWrapper);
   body.append(panelWrapper);
 }

一鍵登錄

Event()

event = new Event(typeArg, eventInit);
// typeArg 是DOMString 類型,表示所創建事件的名稱。
// eventInit 可選,接受以下字段:
// bubbles 是否支持冒泡,cancelable:能否被取消,composed:事件是否會觸發shadow DOM(陰影DOM)根節點之外的事件監聽器

target.dispatchEvent(event)

 const usernameDom = document.getElementById('username');
 const passwordDom = document.getElementById('password');
 const { accountList } = this.state;
 const { username, password } = accountList.find((item) => item.username === handleUsername);

 // 未來可能會廢棄的寫法
 // const evt = document.createEvent('HTMLEvents');
 // evt.initEvent('input', true, true);

 // ie 不支持
 const evt = new Event('input'{ bubbles: true });

 // 將值填入 dom 輸入框裏
 usernameDom.value = username;
 usernameDom.dispatchEvent(evt);
 passwordDom.value = password;
 passwordDom.dispatchEvent(evt);
 
 // 模擬用戶點擊登錄按鈕
 const loginBtn = document.getElementsByClassName('login-btn')[0];
 loginBtn.click();

開發輔助

一鍵重載:Extensions Reloader

即使 Webpack 配置了熱更新,插件打包出來的 JavaScript 代碼更新後也是不能熱加載的,我們可以訪問 chrome://extensions/ 點擊下圖中的小按鈕重新加載,或者安裝 Extensions Reloader (https://chrome.google.com/webstore/detail/extensions-reloader/fimgfedafeadlieiabdeeaodndnlbhid?hl=zh-CN) 插件,點擊按鈕進行重新加載。

安裝擴展文件

Chrome 允許安裝 Chrome 應用市場本地文件兩種來源的擴展文件。訪問 chrome://extensions/,打開 開發者模式,點擊 加載已解壓的擴展程序,就可以選中我們本地的文件了,Edge 等瀏覽器也可以用。

下一階段

目標

設計方向:對插件的使用者增加登錄功能,登錄通過 域賬號 - 密碼 - 業務小組 圈定一個範圍,同一個 業務小組共享 測試賬號、綁定的業務標籤、業務小組關聯的應用。前端本地開發時,項目獲得的賬號通過當前應用所屬的業務小組拉取。

E-R 圖設計

參考文檔


Chrome Developers (https://developer.chrome.com/docs/extensions/mv3/getstarted/)

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/mwZwLVBD2CW2QdlATl9Sog