Windows Terminal 连接 Azure Cloud Shell 的完整设计与源码实现
Windows Terminal 连接 Azure Cloud Shell 的完整设计与源码实现【免费下载链接】terminalThe new Windows Terminal and the original Windows console host, all in the same place!项目地址: https://gitcode.com/GitHub_Trending/term/terminalWindows Terminal 允许用户把 Azure Cloud Shell 当作一个连接直接打开本文以规格文档 Azure cloud shell connector 为骨架完整讲清这一特性的设计动机、认证流程、连接生命周期并深入仓库源码逐条印证ITerminalConnection接口是如何被AzureConnection实现的。读完你能掌握终端连接的抽象模型、基于设备码Device Code Flow的无浏览器认证方案以及令牌存储、多租户选择、WebSocket 建立等关键实现细节。![Azure Cloud Shell 在 Windows Terminal 中作为独立配置文件出现的示意图](https://gitcode.com/GitHub_Trending/term/terminal/blob/20588130d8ef2ba40eb56bdae88e04cce7fc5b5d/doc/specs/?utm_sourcegitcode_repo_files#1235 - Azure cloud shell connector/images/azProf.png)一、设计目标把 Azure 服务带进 Windows Terminal规格文档issue #1235开篇的摘要非常直接这份规格描述了一个功能——让 Windows Terminal 用户连接到 Azure Cloud Shell并包含实现与设计考量。其灵感Inspiration是让开发者在 Windows Terminal 应用内就能顺滑地访问自己的 Azure 服务以方便的方式与 Azure 技术打交道。从仓库的实际落地看这个方便被落实为一项产品能力当平台支持时用户会看到一个名为 Azure Cloud Shell 的动态配置文件见上方配图实际实现中该配置拥有独立图标选中它即可发起一次完整的云端连接。这一能力对应源码中的配置文件生成器 AzureCloudShellGenerator。规格文档同时明确了整个功能必须以隔离方式实现——它对 Windows Terminal 应用本体几乎没有依赖。这样一旦终端支持插件/扩展这个连接器就能直接变成一个插件。这一点在源码中得到忠实贯彻AzureConnection没有侵入终端主流程而是作为一个普通的连接类型存在。二、认证方案设备码流程与 Azure AD v1.0规格文档对认证用户这一步的设计是全文最关键的部分原因有二为什么用设备码流程Device Code Flow因为 Windows Terminal当时不支持拉起浏览器。设备码流程允许用户在一个带屏幕的设备这里就是终端上输入一段短码然后在另一台设备的浏览器里完成登录终端这边通过轮询拿到令牌。为什么用 Azure AD v1.0 而不是 v2.0因为 v2.0即 Microsoft Identity Platform彼时不支持个人账号personal accounts走设备码流程。而 Azure Cloud Shell 用户中个人账号很常见因此选 v1.0。关于令牌的存放规格文档的要求是认证成功后把登录/令牌信息存下来避免用户每次都走一遍设备码流程由于这是敏感信息令牌需加密存储。规格当时指向的是 Windows Storage 加上 Windows Security Data ProtectionDPAPI。这里需要特别指出实现与规格的差异从源码看真正落地采用的是 Windows.Security.Credentials 命名空间下的PasswordVault/PasswordCredential而非规格里设想的 Storage DPAPI 组合。以 AzureConnection.cpp 为例_StoreCredential通过PasswordVault把用户名字段JSON 序列化的租户信息与密码字段JSON 序列化的 accessToken / refreshToken / expiry打包存入资源名固定为Terminal// src/cascadia/TerminalConnection/AzureConnection.cpp void AzureConnection::_StoreCredential() { WDJ::JsonObject userName; userName.SetNamedValue(Lver, WDJ::JsonValue::CreateNumberValue(CurrentCredentialVersion)); _packTenant(userName, *_currentTenant); WDJ::JsonObject passWord; passWord.SetNamedValue(LaccessToken, WDJ::JsonValue::CreateStringValue(_accessToken)); passWord.SetNamedValue(LrefreshToken, WDJ::JsonValue::CreateStringValue(_refreshToken)); passWord.SetNamedValue(Lexpiry, WDJ::JsonValue::CreateStringValue(std::to_wstring(_expiry))); PasswordVault vault; PasswordCredential newCredential{ PasswordVaultResourceName, userName.Stringify(), passWord.Stringify() }; vault.Add(newCredential); }其中CurrentCredentialVersion是一个令牌版本常量当前为 2。源码在_RunAccessState里会读取每条已存凭据的ver字段凡是版本不一致的旧凭据都会被直接移除vault.Remove(entry)只保留最新格式。这是一种平滑的存储格式迁移机制。令牌临近过期时timeNow _expireLimit _expiry其中_expireLimit为 2700 秒会自动走_RefreshTokens刷新并回写。结论规格文档给出了隔离实现 设备码认证 加密令牌存储的设计意图而源码在存储用什么 API这一细节上与原始设想不同但总体方向避免重复登录、安全存储、自动刷新完全一致。三、连接生命周期ITerminalConnection与状态机规格文档中反复强调的核心设计原则是连接器应遵循现有的ITerminalConnection接口使 Azure 只是Windows Terminal 能建立的一种连接类型。这个接口定义在 ITerminalConnection.idl是终端所有后端连接本地 ConPTY、远程、Azure 等的统一抽象interface ITerminalConnection { void Initialize(Windows.Foundation.Collections.ValueSet settings); void Start(); void WriteInput(Char[] data); void Resize(UInt32 rows, UInt32 columns); void Close(); event TerminalOutputHandler TerminalOutput; event Windows.Foundation.TypedEventHandlerITerminalConnection, Object StateChanged; Guid SessionId { get; }; ConnectionState State { get; }; };配套的ConnectionState枚举NotConnected / Connecting / Connected / Closing / Closed / Failed就是连接状态的通用词汇。规格文档所说的以隔离方式实现、将来可变成插件本质就是让AzureConnection实现这五个方法加两个事件从而即插即用地挂进终端的连接体系。AzureConnection 的内部状态机AzureConnection在 AzureConnection.h 里定义了一个更细的业务状态机AzureState用来描述从拿到账号到进入云端终端的完整过程状态含义对应实现方法AccessStored检查是否已有保存的凭据让用户选择复用/新登录/删除_RunAccessStateDeviceFlow无凭据或用户选择新账号走设备码认证_RunDeviceFlowStateTenantChoice账号有多个租户需用户选择_RunTenantChoiceStateStoreTokens询问是否保存本次凭据供下次使用_RunStoreStateTermConnecting已备齐 tenantID / 令牌发起连接_RunConnectStateTermConnected已进入云端终端循环读取 WebSocket在_OutputThread中内联处理驱动这台状态机的是Start()里创建的一条输出线程_OutputThread见 AzureConnection.cpp。线程内是一个switch(_state)大循环每处理完一个状态就推进到下一个直到TermConnected后进入 WebSocket 读取循环。这里体现了规格中认证、申请 cloud shell、申请终端走 HTTP连接终端走 WebSocket的分层设计。几个值得注意的实现事实均可在源码确认ConnectionTypeGUID每个连接类型都有全局唯一标识AzureConnection的是{0xd9fcfdfa, 0xa479, 0x412c, {0x83, 0xb7, 0xc5, 0x64, 0xe, 0x61, 0xcd, 0x62}}。配置文件正是靠这个 GUID 关联到AzureConnection。IsAzureConnectionAvailable()返回AzureClientID ! L0。规格与源码注释都说明客户端 ID 只在正式发布流水线里注入本地构建会得到占位值0因此本地构建会主动禁用 Azure 连接避免连不上还白报错。Initialize解析初始尺寸与会话从settings里读取initialRows / initialCols / sessionId若sessionId为空则用Utils::CreateGuid()生成一个。Resize在已连接时会向{cloudShellUri}terminals/{id}/size?colsrowsversion2019-01-01发请求从而把本地窗口缩放同步到云端终端。四、从规格到落地HTTP WebSocket 的实现规格文档提出前三步认证、请求 cloud shell、请求 terminal用 HTTP最后一步连接终端用 WebSocket并点名了 cpprestsdk 作为 HTTP 客户端库理由同为微软维护出问题便于内部协同。这里再次出现实现与规格的偏差值得如实说明从源码看HTTP 请求用的是 WinRT 的winrt::Windows::Web::Http::HttpClient封装在_SendRequestReturningJson中而 WebSocket 升级用的是 WinHttp 系列 APIWinHttpOpen→WinHttpConnect→WinHttpOpenRequest→WinHttpWebSocketCompleteUpgrade并没有引入 cpprestsdk。也就是说规格里的库选型在落地时被替换成了 Windows 原生的 WinRT / WinHttp 方案。这一点对理解规格文档与最终代码的关系很典型规格记录的是设计阶段的判断代码才是最终事实。关键的连接建立逻辑集中在_RunConnectState与_GetTerminal拉取用户云控制台设置_GetCloudShellUserSettings从properties.preferredShellType解析用户偏好的 shell缺省回退到pwsh_ParsePreferredShellType。申请一个 cloud shell_GetCloudShell向providers/Microsoft.Portal/consoles/default发PUT请求体固定{properties: {osType: linux}}拿到properties.uri作为_cloudShellUri。为该 cloud shell 申请一个 terminal_GetTerminal向{uri}terminals?colsrowsversion2019-01-01shell{shellType}发POST拿到终端id。推导 WebSocket 端点源码对两种形态做了区分处理——若 cloud shell URI 不含servicebus直接把它https换成wss再拼上terminals/{id}若含servicebus则按 cloud shell 团队自己的规则把 socket URI 重排为.../$hc/{ns}/terminals/{id}。注释明确写道这里的逻辑基于 cloud shell 团队自身的方式。升级到 WebSocket后进入TermConnected在输出线程里用WinHttpWebSocketReceive循环读取把 UTF8/BINARY 消息经til::u8u16转码后通过TerminalOutput事件抛给终端 UI。用户输入侧WriteInput在已连接且已进入 TermConnected时直接把数据以WINHTTP_WEB_SOCKET_UTF8_MESSAGE_BUFFER_TYPE发到 WebSocket否则认证阶段会做本地回显、处理退格、按InputMode::Line收集整行输入供认证流程_ReadUserInput读取。五、配置与使用动态配置文件如何出现规格文档在 UI/UX 一节只说会多出一个新配置文件选项实现时会配独立图标。落到仓库里这个多出来的配置文件是由 AzureCloudShellGenerator 作为动态配置文件生成器注入的而非写死在用户 JSON 里// src/cascadia/TerminalSettingsModel/AzureCloudShellGenerator.cpp void AzureCloudShellGenerator::GenerateProfiles( std::vectorwinrt::com_ptrimplementation::Profile profiles) const { if (AzureConnection::IsAzureConnectionAvailable()) { auto azureCloudShellProfile{ CreateDynamicProfile(LAzure Cloud Shell) }; azureCloudShellProfile-StartingDirectory(winrt::hstring{ DEFAULT_STARTING_DIRECTORY }); azureCloudShellProfile-DefaultAppearance().DarkColorSchemeName(LVintage); azureCloudShellProfile-DefaultAppearance().LightColorSchemeName(LVintage); azureCloudShellProfile-ConnectionType(AzureConnection::ConnectionType()); profiles.emplace_back(std::move(azureCloudShellProfile)); } }可以推断出几个使用层面的事实可用性与构建相关IsAzureConnectionAvailable()为假如本地构建时这个配置文件根本不会生成——这也解释了为什么有些 Windows Terminal 安装里看不到 Azure Cloud Shell。外观走 Vintage 配色无论深色还是浅色外观默认都用Vintage配色方案并设置了独立的生成器图标ProfileGeneratorIcons/AzureCloudShell.png。连接类型由 GUID 关联ConnectionType(AzureConnection::ConnectionType())把配置文件绑定到前面那个固定 GUID打开时终端据此实例化AzureConnection。六、能力边界可访问性、安全、可靠性与性能规格文档专设了 Capabilities 一节评估各维度影响这里完整继承其结论可访问性该功能不影响 Windows Terminal 的无障碍能力。安全任何联网功能都引入安全风险文档认为通过正确使用 Azure AD v1.0 并谨慎保管服务端下发的令牌可把风险降到可控范围。从源码看令牌只经PasswordVault这类系统级凭据存储不落明文。可靠性 / 性能 / 功耗 / 效率文档判断这些维度均不受影响。兼容性正因为实现与终端本体基本解耦文档认为不会有既有代码或行为被破坏。七、潜在风险与未来方向规格文档如实列出了三条潜在问题值得读者保留依赖 cpprestsdk 这一开源项目——其代码问题会波及本功能注落地实现已改用 WinRT/WinHttp此条在实现中实际已被规避。Azure AD v1.0 可能被弃用——目前仍受支持但未来有风险文档给出的兜底是最坏情况可切换到 Microsoft Identity Platform只需少量修改 HTTP 请求。Azure Cloud Shell 的 API 并非公开——正式落地需要 Azure Cloud Shell 团队授予应用权限构成一项额外依赖。文档结尾还提出一个展望一旦 Windows Terminal 允许插件/扩展这个 Azure 连接器有可能是终端的第一个插件。这与全文反复出现的隔离实现、可插拔主线呼应也解释了为何源码始终让AzureConnection只通过ITerminalConnection与终端对话。小结本文以 规格文档 为主线还原了认证 → 请求 cloud shell → 请求 terminal → WebSocket 连接的完整链路并逐条对照仓库源码 AzureConnection.cpp / AzureConnection.h / AzureCloudShellGenerator.cpp / ITerminalConnection.idl 印证了实际实现。需要记住的关键差异是令牌存储从规格的 Storage DPAPI 变成了PasswordVaultHTTP/WebSocket 从 cpprestsdk 变成了 WinRT/WinHttp 原生 API——规格记录设计意图代码才是最终事实两者结合阅读才能完整理解这一特性的全貌。【免费下载链接】terminalThe new Windows Terminal and the original Windows console host, all in the same place!项目地址: https://gitcode.com/GitHub_Trending/term/terminal创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

相关新闻

越痛苦的学习越高效?科学区分有效困难与无效消耗

越痛苦的学习越高效?科学区分有效困难与无效消耗

有一段时间我在学一个不算熟的技术框架。白天看文档,晚上把重点摘到笔记软件里,段落分类、颜色标注都做得整整齐齐。整个学习过程非常舒服,几乎没有卡壳,甚至有一种“今天摄入量很大”的满足感。结果一周之后,接到一个…

2026/11/12 1:17:40 阅读更多 →
Lucide React 图标导出实操手册:3 步跑通完整导出流程,附 5 个避坑自查项

Lucide React 图标导出实操手册:3 步跑通完整导出流程,附 5 个避坑自查项

Lucide React 图标导出实操手册:3 步跑通完整导出流程,附 5 个避坑自查项 【免费下载链接】lucide Beautiful & consistent icon toolkit made by the community. Open-source project and a fork of Feather Icons. 项目地址: https://gitcode.co…

2026/10/24 14:32:22 阅读更多 →
逆矩阵计算总出错?从矩阵运算定义到方法选择全解析

逆矩阵计算总出错?从矩阵运算定义到方法选择全解析

晚上十点,你打开 Day36 的线代每日一题。题目要求做逆矩阵计算,旁边还标着矩阵运算定义、矩阵运算。一看“逆矩阵”三个字,很多人会立刻把伴随矩阵、初等行变换、公式法在脑子里过一遍,然后开始套流程。但真正落笔时,往…

2026/11/11 4:51:38 阅读更多 →

最新新闻

Electron桌面应用开发实战:从环境搭建到打包发布全流程

Electron桌面应用开发实战:从环境搭建到打包发布全流程

做前端这些年,我大部分时间都在跟浏览器标签页打交道,直到第一次把桌面应用跑起来,才发现原来自己一直被限制在地址栏和刷新按钮围起来的框框里。Electron这个词,最开始是在某段时间频繁出现在同事的讨论里,一个用HTML…

2026/11/10 23:32:01 阅读更多 →
滑盖智能锁T109深度解析:结构原理、安装调试与故障排查

滑盖智能锁T109深度解析:结构原理、安装调试与故障排查

简介:亚太天能T109滑盖智能锁产品说明书是一份PDF格式的官方技术文档,主要面向智能锁安装人员、终端用户及售后维护者,帮助快速掌握产品安装、配置与常见故障处理。全包仅1个PDF文件,大小4.37MB,内容结构清晰&#xff…

2026/11/10 23:32:03 阅读更多 →
PMSM弱磁控制原理与Simulink建模:高速AGV驱动系统设计指南

PMSM弱磁控制原理与Simulink建模:高速AGV驱动系统设计指南

上个月我在调试一台高速AGV的驱动系统,整车要求空载跑到8m/s,电机转速已经拉到额定点,驱动器的输出电压也顶到了母线电压极限附近。再往上踩速度指令,转速纹丝不动,三相电流反而开始震荡。那会儿我的第一反应就是&…

2026/11/11 2:31:33 阅读更多 →
C++核心知识点:从内存管理到STL的实战指南

C++核心知识点:从内存管理到STL的实战指南

C 这门语言我前前后后折腾了十几年,用它写过嵌入式驱动、做过游戏服务端,也搭过基础组件库。每次看到新人一头扎进"C 核心知识点"这个搜索词,我其实挺感慨的——这门语言的难点从来不是语法多,而是知识点之间的耦合太深…

2026/11/11 17:16:37 阅读更多 →
T109滑盖智能锁怎么装?安装调试与故障排查全攻略

T109滑盖智能锁怎么装?安装调试与故障排查全攻略

简介:亚太天能T109滑盖智能锁产品说明书以PDF格式发布,适合智能锁用户、安装人员与售后维修人员阅读。内容围绕T109系列指纹密码刷卡锁展开,先介绍前面板、后面板、锁体、机械钥匙、电池盒盖等部件名称与功能,再给出完整安装步骤&…

2026/11/11 17:16:37 阅读更多 →
LLM知识降熵:从信息垄断到理解权下放

LLM知识降熵:从信息垄断到理解权下放

你有没有过这种经历:翻开源码注释、论文摘要或者一份专业报告,每个字都认识,连在一起却像天书。想找人聊聊,身边要么没人懂,要么懂的懒得跟你解释。后来我试着把同一段内容丢给一个大语言模型,几秒钟之后&a…

2026/11/10 23:32:10 阅读更多 →

日新闻

周新闻

月新闻