news 2026/9/10 12:53:54

JumpServer Chrome 网页小应用(Web Applet)深度解析:Selenium 版本约束、账号代填机制与安全模式实现

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
JumpServer Chrome 网页小应用(Web Applet)深度解析:Selenium 版本约束、账号代填机制与安全模式实现

JumpServer Chrome 网页小应用(Web Applet)深度解析:Selenium 版本约束、账号代填机制与安全模式实现

【免费下载链接】jumpserverJumpServer is an open-source Privileged Access Management (PAM) platform that provides DevOps and IT teams with on-demand and secure access to SSH, RDP, Kubernetes, Database and RemoteApp endpoints through a web browser.项目地址: https://gitcode.com/GitHub_Trending/ju/jumpserver

JumpServer 的 Chrome 小应用(Applet)是终端连接 Web 类资产的核心组件:它在本地拉起真实 Chrome 浏览器,借助 Selenium 自动完成登录页面的账号代填,从而让用户在 Web 资产上也能获得与 SSH/RDP 一致的托管式访问体验。本文以 README_EN.md 为线索,结合同目录下 app.py、main.py、common.py 等源码,完整讲解其运行环境约束、代填两种模式、步骤指令集、安全模式扩展与本地调试方法。读完本文,你将掌握该小应用从清单配置、参数传人到浏览器启动与进程清理的完整链路,能够自行定位"版本不匹配""代填失败""新标签页拦截"等常见问题。

一、Chrome 小应用在 JumpServer 中的定位

在 JumpServer 的终端体系中,apps/terminal/applets/目录存放着各类连接小应用,Chrome 小应用即其中的 Web 浏览器应用。它由 manifest.yml 声明:

name: chrome display_name: "{{ 'Chrome Browser' | trans }}" version: 1.3 comment: "{{ 'Chrome Browser Open URL Page Address' | trans }}" author: JumpServer Team exec_type: python update_policy: always type: web tags: - web protocols: - http
  • type: webprotocols: http表明该小应用面向 Web 类资产,通过 HTTP/HTTPS 打开页面地址;
  • exec_type: python表示它以 Python 程序执行,入口即 main.py;
  • update_policy: always表示小应用更新时始终覆盖安装;
  • version: 1.3与 ChangeLog 中的最新版本号一致。

其基本工作模式为:用户在 JumpServer Web 界面点击连接 Web 资产 → 终端组件将资产、账号、平台等信息以 Base64 编码的 JSON 传给小应用 → 小应用启动本地 Chrome(Selenium 驱动)→ 打开资产地址并自动完成登录代填 → 将浏览器窗口交给用户操作。

二、运行环境约束:Selenium 版本与 Chrome/ChromeDriver 匹配

README_EN.md 对运行环境给出了两条明确约束:

  • Selenium 版本固定为 4.4.0
  • Chrome 与 ChromeDriver 版本必须匹配(ChromeDriver 需从官方下载渠道获取与本地 Chrome 主版本一致的驱动)。

这两条约束在小应用源码中均有对应体现。app.py 中启动浏览器的核心代码为:

self.service = Service() # driver 的 console 终端框不显示 self.service.creationflags = CREATE_NO_WINDOW self.driver = webdriver.Chrome(options=self._chrome_options, service=self.service) self.driver.implicitly_wait(10)

Service()默认会在本机寻找chromedriver,因此若本机 Chrome 与 ChromeDriver 主版本不一致,Selenium 会在创建webdriver.Chrome时直接抛出SessionNotCreatedException之类的错误。这是该小应用最常见的启动失败原因之一,排查时应先用chromedriver --versionchrome --version(Windows 下可在chrome://version查看)核对两者主版本号一致。

从源码结构看,该小应用的交互逻辑大量依赖 Selenium 的 WebDriver API:find_element定位元素、send_keys输入、click点击、switch_to.frame切换 iframe、implicitly_wait设置隐式等待(默认 10 秒),这些都是 Selenium 4.x 的标准用法,也解释了为什么版本被严格锁定在 4.4.0。

三、小应用安装与版本演进:setup.yml 与 ChangeLog

与多数小应用一样,Chrome 小应用通过 setup.yml 描述安装方式:

type: manual # exe, zip, manual source: arguments: destination: program: md5:

type: manual表示该小应用不需要额外下载安装包,直接以目录形式分发,由 JumpServer 终端组件将整个chrome目录作为应用载体。

版本历史记录在 ChangeLog,可以清晰看到其能力演进脉络:

版本日期类型内容
1.32025-07-25Bug 修复修复 Chrome 密码管理器弹窗的问题
1.22025-05-30功能更新新增用户配置的语言支持,默认使用系统当前语言
1.12024-10-24功能优化优化快速点击造成页面卡住的问题
1.02023-09-18Bug 修复移除窗口最小化,避免造成部分页面元素定位失败
0.92023-09-04功能优化进度条显示最大超时
0.82023-08-16功能优化修复代填失败,造成页面卡住的问题
0.72023-07-28功能优化增加进度窗口,隐藏代填操作
0.62023-07-13功能优化优化 Chrome 插件拦截逻辑
0.52023-07-06功能更新增加匿名用户的支持,如果账号是匿名用户,username 和 secret 则为空

这些演进点(密码管理器弹窗、语言支持、进度窗口、匿名账号、插件拦截等)都直接对应 app.py 与 common.py 中的具体实现,下文将逐一展开。

四、输入数据:Base64 JSON 与数据模型

小应用通过命令行参数接收一次连接所需的所有上下文。main.py 的入口逻辑非常精简:

def main(): base64_str = sys.argv[1] data = convert_base64_to_dict(base64_str) applet_app = AppletApplication(**data) block_input() applet_app.run() unblock_input() applet_app.wait()
  • 终端组件将连接参数序列化为 JSON 后再做 Base64 编码,作为第一个命令行参数传入;
  • common.py 的convert_base64_to_dict负责解码并还原为 dict;
  • 连接期间调用block_input()锁定用户键盘鼠标输入,避免用户在自动代填过程中干扰页面操作,代填完成后unblock_input()解锁。

仓库提供了完整的调试样例 test_data_example.json,展示了输入数据的完整结构:

{ "protocol": "web", "user": { "id": "2647CA35-5CAD-4DDF-8A88-6BD88F39BB30", "name": "Administrator", "username": "admin" }, "asset": { "id": "46EE5F50-F1C1-468C-97EE-560E3436754C", "name": "test_baidu", "address": "https://www.baidu.com", "category": { "value": "web", "label": "web" }, "protocols": [ { "id": 2, "name": "http", "port": 80 } ], "specific": { "autofill": "basic", "username_selector": "name=username", "password_selector": "name=password", "submit_selector": "id=login_button", "script": [] } }, "account": { "id": "9D5585DE-5132-458C-AABE-89A83C112A83", "name": "test_mysql", "username": "root", "secret": "" }, "platform": { "charset": "UTF-8" } }

对应的数据模型定义在 common.py:

  • User:当前登录用户(id/name/username);
  • Asset:Web 资产,含address(要打开的 URL)、protocolscategoryspec_info(即样例中的specific,Web 类资产的代填配置);
  • Account:代填账号,含usernamesecret(密码/密钥),secret_type描述密钥类型;
  • Platform:平台信息,通过get_protocol_setting("http")可取到该协议下的默认代填设置ProtocolSetting
  • ConnectOption:连接选项,包含lang(语言)、charset等。

AssetPlatform都提供了get_protocol_setting/get_protocol_port之类的便捷方法,小应用据此决定以哪一套配置执行代填。

五、账号自动代填:basic 与 script 两种模式

账号代填是 Chrome 小应用的核心能力,实现在 app.py 的WebAPP类中。代填策略按"优先级"解析:先看资产自身的spec_info.autofill,若资产未配置,则回退到平台的 HTTP 协议设置platform.get_protocol_setting("http").autofill

extra_data = self.asset.spec_info autofill_type = extra_data.autofill if not autofill_type: protocol_setting = self.platform.get_protocol_setting("http") ... extra_data = protocol_setting autofill_type = extra_data.autofill

5.1 basic 模式:选择器三步代填

autofill == "basic"时,使用_default_custom_steps生成固定三步:

return [ Step({"step": 1, "value": self._account_username, "target": spec_info.username_selector, "command": "type"}), Step({"step": 2, "value": self._account_secret, "target": spec_info.password_selector, "command": "type"}), Step({"step": 3, "value": "", "target": spec_info.submit_selector, "command": "click"}) ]

对应平台/资产需配置三个选择器字段(见 common.py 的Specific/ProtocolSetting):

  • username_selector:用户名输入框定位表达式;
  • password_selector:密码输入框定位表达式;
  • submit_selector:登录按钮定位表达式。

样例中"name=username""id=login_button"的写法即"定位方式=值"格式,支持的定位方式见下文的指令集章节。

5.2 script 模式:步骤脚本与占位符

autofill == "script"时,使用资产/平台配置的脚本步骤:

script_list = extra_data.script steps = sorted(script_list, key=lambda step_item: step_item.step) for item in steps: val = item.value if val: val = val.replace("{USERNAME}", self._account_username) val = val.replace("{SECRET}", self._account_secret) item.value = val self._steps.append(item)

要点:

  • 脚本按step字段升序执行,适合登录流程复杂的页面(如先输用户名、点下一步、再输密码、最后提交);
  • 步骤的value中支持两个内置占位符:{USERNAME}替换为账号用户名,{SECRET}替换为账号密码/密钥;
  • 每个Step包含step(序号)、target(元素定位)、command(指令类型)、value(输入值)。

5.3 匿名账号支持

对应 ChangeLog v0.5 的"匿名用户"特性:当account.username == "@ANON"时,用户名与密钥均置空,代填步骤中的账号信息为空串(app.py),适用于无需登录即可访问的公开页面。

六、步骤指令集:type / click / open / code / select_frame / sleep

StepAction(app.py)是单步指令的执行器,指令类型由Command枚举定义:

class Command(Enum): TYPE = 'type' CLICK = 'click' OPEN = 'open' CODE = 'code' SELECT_FRAME = 'select_frame' SLEEP = 'sleep'

6.1 元素定位方式映射

target采用方式=值的字符串格式,methods_map支持以下定位方式(大小写不敏感):

写法底层 Selenium 定位
name=xxxBy.NAME
id=xxxBy.ID
class_name=xxxBy.CLASS_NAME
css=xxx/css_selector=xxxBy.CSS_SELECTOR
xpath=xxxBy.XPATH

未匹配到已知方式时回退为By.NAME。例如样例中的"name=username"即按表单控件的name属性定位。

6.2 各指令行为

  • open:打开地址,url = value or target,为空则跳过,等价于driver.get(url)
  • type:向定位到的元素send_keys(value),即输入账号/密码;
  • click:对定位元素执行click()
  • code:弹出一个交互式输入对话框(见下节CodeDialog),用户输入内容后写入当前定位元素——适用于验证码等无法预填的字段;
  • select_frame:切换到目标 iframe,target支持三种格式(_switch_iframe的实现):
    • index=1:按索引切换;index为负数时switch_to.default_content()回到顶层文档;
    • id=xxx:按 iframe 的 id 切换;
    • name=xxx:按 iframe 的 name 切换;
    • 其他格式直接作为 frame 引用切换;
  • sleeptime.sleep(int(target))target无法转为整数时至少休眠 1 秒,用于等待页面异步加载。

每一步通过execute_action包装执行,任一指令抛出异常都会返回False,此时WebAPP.execute会调用notify_err_message弹出错误提示(提示内容含失败的targetcommand)并中止代填流程,避免"代填失败造成页面卡住"(对应 ChangeLog v0.8)。

七、浏览器启动参数与安全模式

7.1 默认浏览器选项

default_chrome_driver_options(app.py)集中定义了 Chrome 启动参数:

options.add_argument("--start-maximized") # 忽略证书错误相关 options.add_argument('--ignore-ssl-errors') options.add_argument('--ignore-certificate-errors') options.add_argument('--ignore-certificate-errors-spki-list') options.add_argument('--allow-running-insecure-content') # 禁用开发者工具 options.add_argument("--disable-dev-tools") # 禁用 密码管理器弹窗 prefs = { "credentials_enable_service": False, "profile.password_manager_enabled": False, "intl.accept_languages": languag, } options.add_experimental_option("prefs", prefs) # chromedriver 退出后也不关闭浏览器 options.add_experimental_option("detach", True) options.add_experimental_option("excludeSwitches", ['enable-automation'])

几个关键点与 ChangeLog 的 Bug 修复一一对应:

  • 禁用密码管理器弹窗credentials_enable_serviceprofile.password_manager_enabled置为False,正是 v1.3"修复 Chrome 密码管理器弹窗问题"的实现手段;
  • excludeSwitches: ['enable-automation']:去掉 Chrome 的"自动化测试"提示条;
  • detach: True:chromedriver 退出后浏览器进程不被连带关闭;
  • 证书相关参数用于访问自签名证书的 HTTPS 页面。

7.2 应用窗口与临时用户目录

AppletApplication.__init__(app.py)中为本次连接创建独立配置:

self._tmp_user_dir = tempfile.TemporaryDirectory() lang = self.connect_option.lang if self.connect_option.lang else get_system_language() self._chrome_options = default_chrome_driver_options(languag=lang) self._chrome_options.add_argument("--app={}".format(self.asset.address)) self._chrome_options.add_argument("--user-data-dir={}".format(self._tmp_user_dir.name))
  • --app=<url>让 Chrome 以"应用窗口"模式打开资产地址(无地址栏/标签栏),对应 v1.0"移除窗口最小化,避免页面元素定位失败"的调整;
  • 每次连接使用tempfile.TemporaryDirectory()生成的临时--user-data-dir,隔离浏览器缓存与 Cookie,连接结束后由close()清理。

7.3 安全模式扩展

当平台 HTTP 协议设置了safe_mode时,小应用会加载内置浏览器扩展disable_new_tab_window_menu(manifest.json):

if protocol_setting and protocol_setting.safe_mode: extension_paths = load_extensions() self._chrome_options.add_argument('--load-extension={}'.format(','.join(extension_paths)))

扩展包含三个文件,对应 v0.6"优化 Chrome 插件拦截逻辑":

  • background.js:监听标签页创建/更新事件,拦截chrome://newtab/与所有chrome://页面;当打开的新标签页与首个标签页域名不同(按主域名比较,取最后两段)时直接chrome.tabs.remove关闭,从而保证用户始终停留在被授权访问的站点;
  • content_script.js:通过MutationObserver将所有<a>链接的target改为_self(当前窗口打开)、重写window.open强制当前页跳转、屏蔽右键菜单、拦截 F12 / F1 以及除 Ctrl+P/C/F/V 外的所有 Ctrl 组合键(防止打开开发者工具);
  • 扩展在页面加载完成(document_end)时注入,权限仅申请tabs

八、交互体验细节:输入锁定、进度条与语言支持

8.1 全局输入锁定

common.py 在 Windows 平台通过user32.BlockInput实现键盘鼠标锁定与解锁:

_blockInput = ctypes.windll.user32.BlockInput _blockInput.argtypes = [wintypes.BOOL] def block_input(): if _blockInput: _blockInput(True) def unblock_input(): if _blockInput: _blockInput(False)

代填过程全程锁定输入,防止用户在自动化操作期间误触页面;code指令输入验证码时则临时unblock_input()再锁定。

8.2 全屏进度条与最大超时

code_dialog.py 提供了两类 UI 组件:

  • CodeDialog:基于tkinter的单行输入对话框,支持回车确认,空输入会弹出 warning,用于code指令的验证码等手动输入;
  • TkProgressBar:全屏置顶的 indeterminate 进度条,wait_max_time = 3000 * 10(即 30 秒)。wrapper_progress_bar装饰器将其套在run()外层——在后台线程中执行浏览器启动与代填,同时前台显示"隐藏代填操作"的全屏进度动画,超时自动销毁窗口。这正是 ChangeLog v0.7(增加进度窗口,隐藏代填操作)与 v0.9(进度条显示最大超时)的实现。
class TkProgressBar(object): # 30s wait_max_time = 3000 * 10

8.3 语言支持

对应 v1.2"新增用户配置的语言支持,默认使用系统当前语言":语言优先级为connect_option.lang(用户在 JumpServer 连接配置中指定的语言)→get_system_language()(common.py,Windows 下读取GetUserDefaultUILanguage转换语言代码,失败回退en_US)。该语言同时作用于:

  • intl.accept_languages偏好(浏览器接受语言);
  • --lang=<lang>启动参数(Chrome 界面语言)。

九、连接生命周期:进程监控与清理

9.1 等待浏览器退出

wait()(app.py)负责管理进程生命周期:

parent_id = self.service.process.pid pids = get_children_pids(parent_id) ... # 退出 chromedriver 进程,等待所有子进程退出 self.service.stop() while True: time.sleep(5) for pid in pids_status: pids_status[pid] = check_pid_alive(pid) ...
  • 先通过wmic查询 chromedriver 的子进程(get_children_pids,Windows 专属);
  • 停掉 chromedriver 服务,但依赖detach选项让浏览器继续运行;
  • 每 5 秒用tasklistcheck_pid_alive)轮询所有子进程,全部退出后wait结束,小应用随之退出。

9.2 关闭与清理

close()调用driver.quit()关闭全部浏览器窗口,并清理本次连接创建的临时用户数据目录_tmp_user_dir

十、本地调试与验证

无需部署完整 JumpServer,也可在装有 Python 3 + Selenium 4.4.0 + Chrome/ChromeDriver 的 Windows 机器上单独运行该小应用:

  1. 确认pip show selenium版本为 4.4.0,确认chromedriver --version与 Chrome 主版本一致;
  2. 修改 test_data_example.json,将asset.address换成目标 URL,并按页面实际情况调整specific中的username_selector/password_selector/submit_selector(支持id=/name=/css=/xpath=等写法);
  3. 在仓库根目录执行:
cd apps/terminal/applets/chrome python -c "import base64,json;print(base64.b64encode(open('test_data_example.json','rb').read()).decode())" > /tmp/data.b64 python main.py "$(cat /tmp/data.b64)"

小应用将拉起 Chrome 打开资产页面并自动执行代填步骤,可借此验证选择器表达式是否有效、iframe 切换与 sleep 时机是否合理,再回到 JumpServer 平台侧完善资产/平台的代填配置。

结语

Chrome 小应用虽然文档极简,但其源码完整覆盖了 Web 资产托管访问的关键工程问题:Selenium 版本与驱动的严格匹配(README 的核心约束)、basic/script 两套代填策略、六种页面操作指令、安全模式下的标签页拦截扩展,以及输入锁定、进度窗口、语言适配等体验细节。理解 app.py 与 common.py 的实现,是排查该小应用连接失败与代填异常的最直接路径;而 ChangeLog 则记录了它的每一次演进,可作为版本升级时的回归检查清单。

【免费下载链接】jumpserverJumpServer is an open-source Privileged Access Management (PAM) platform that provides DevOps and IT teams with on-demand and secure access to SSH, RDP, Kubernetes, Database and RemoteApp endpoints through a web browser.项目地址: https://gitcode.com/GitHub_Trending/ju/jumpserver

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/10 12:52:19

Python论文格式检查系统:从python-docx解析到LLM辅助的全流程实现

简介&#xff1a;这套基于Python的论文格式检查与处理源码&#xff0c;主要面向需要批量规范学术稿件格式的研究人员、期刊编辑以及有文本处理需求的Python开发者&#xff0c;可自动识别并修正标题层级、摘要、章节编号、图表标注、引用和参考文献等常见格式问题&#xff0c;显…

作者头像 李华
网站建设 2026/9/10 12:51:31

JavaWeb企业人事管理系统开发全解析:MySQL数据库设计到Tomcat部署实战

简介&#xff1a;这套基于JavaWeb的企业人事管理系统源码与数据库压缩包&#xff0c;专为计算机相关专业正在准备毕业设计的学生&#xff0c;以及需要项目实战练习的Java学习者打造。系统基于经典B/S结构&#xff0c;后台采用JSP、Servlet、JDBC技术组合&#xff0c;数据库使用…

作者头像 李华