真高效!實現不同環境下賬號一鍵登錄
前言
在我們的工作過程中,每當需要排查問題、跑冒煙用例、看測試環境的效果時,經常需要在瀏覽器環境中切換登錄賬號,另外,在開發的過程中,也需要在編輯器 VS Code 裏切換代理登錄的賬號。
以政採雲的業務開發爲例:訪問測試、預發等不同環境要切賬號,切換不同角色身份、不同地理區劃、甚至查看有特殊數據時也要切賬號…… 這讓我們的工作中充斥了大量的輸入賬號密碼的無效時間,也需要我們額外維護賬號文檔,非常苦惱。
關於在 VS Code 編輯器裏快捷切換賬號的工具,我們已經有同學設計開發過,在後續的文章中會向大家展示。
本文將講述一下如何在瀏覽器環境,擴展 Chrome 瀏覽器原有的 “記住密碼” 功能,實現快捷登錄、隔離賬號信息以及備註標籤等方便使用的功能,同時分享給測試、後端、產品等其他的夥伴,提高大家的效率,希望這次探索能給更多的人帶來啓發。
需求分析
-
支持賬號錄入和一鍵登錄,節約輸入時間
-
對賬號進行個性化的 tag 標記,支持增刪改查
-
隔離不同環境下的賬號,解決混用的干擾
-
方便查看和數據維護
-
友好的 UI 界面
最終效果預覽
主要演示一下插件的位置,其中,刪除和置頂是常見功能,就不在這裏演示了
一鍵登錄
賬號錄入
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:擴展名,顯示在我的擴展文件中
-
manifest_version:標記 manifest.json 文件的版本號。從 Chrome 18 版本起, manifest_version 需不小於 2, 並且,由於 manifest_version 爲 3 的部分語法僅在 Chorme 88 以上支持,Edge、Firefox 等其他瀏覽器都不支持,所以 manifest_version 爲 2 是更多擴展程序的選擇。
-
icons:擴展程序顯示在右上角的圖標,需要配置不同規格的圖片,適應不同的顯示需要。
{
"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 (https://developer.mozilla.org/zh-CN/docs/Web/API/Event)。該方法 IE 瀏覽器不支持。
event = new Event(typeArg, eventInit);
// typeArg 是DOMString 類型,表示所創建事件的名稱。
// eventInit 可選,接受以下字段:
// bubbles 是否支持冒泡,cancelable:能否被取消,composed:事件是否會觸發shadow DOM(陰影DOM)根節點之外的事件監聽器
target.dispatchEvent(event)
- 向一個指定的事件目標派發一個事件,從而觸發監聽函數的執行。該方法返回一個布爾值,只要有一個監聽函數調用了 target.dispatchEvent 則返回 false,否則返回 true。
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 等瀏覽器也可以用。
下一階段
目標
-
將數據存儲到後端,避免數據丟失問題。
-
將數據共享到前端 VSCode 插件上,提供給快速本地代理使用。
-
新增用戶登錄功能,打通同一使用者訪客身份數據共用問題。
-
隔離業務小組,避免 Tag 混用、全量賬號查找不便問題。
-
一鍵打開 Chrome 訪客身份並登錄,同時操作多個賬號,方便測試使用。
設計方向:對插件的使用者增加登錄功能,登錄通過 域賬號 - 密碼 - 業務小組 圈定一個範圍,同一個 業務小組共享 測試賬號、綁定的業務標籤、業務小組關聯的應用。前端本地開發時,項目獲得的賬號通過當前應用所屬的業務小組拉取。
E-R 圖設計
參考文檔
Chrome Developers (https://developer.chrome.com/docs/extensions/mv3/getstarted/)
本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源:https://mp.weixin.qq.com/s/mwZwLVBD2CW2QdlATl9Sog