WSL 里的 CLI,为什么能直接唤起 Windows 浏览器

📅 2026/7/28 14:13:06
WSL 里的 CLI,为什么能直接唤起 Windows 浏览器
今天做一个统一授权功能,其中有一项很具体的要求:命令行程序不能再让用户手工配置一串长期密钥,它应该像现在常见的开发者 CLI 一样,输入登录命令,去浏览器完成身份验证和授权,然后回到终端继续工作。我先写了一个很小的 Python Demo。在 WSL 的终端里运行后,Windows 上的默认浏览器直接弹了出来。import webbrowser webbrowser.open(authorize_url)这段代码简单得有点可疑。Python 运行在 Linux 里,Chrome 或 Edge 明明装在 Windows 上,中间没有写explorer.exe,也没有判断 WSL,为什么它知道该去宿主机开浏览器?更有意思的是,浏览器能打开,并不意味着授权一定能顺利回到 CLI。浏览器最后访问127.0.0.1时,Windows 和 WSL 对“本机”的理解可能并不一致。这正好把 CLI 登录背后的几层机制都翻了出来。先把完整流程走一遍这个 Demo 使用的是 OAuth 2.0 Authorization Code + PKCE。为了不带入某个具体产品,下面把服务都写成通用地址:https://login.example.com/authorize https://login.example.com/token https://api.example.com/resourceCLI 启动时会做几件事:生成一次性的state、nonce和 PKCEcode_verifier;由code_verifier计算code_challenge;在本机启动一个短命的 HTTP 回调监听器;打开系统浏览器访问授权地址;用户在浏览器登录并确认授权;浏览器跳转到本机回调地址并携带一次性code;CLI 校验state,再用code + code_verifier换取 token;使用 access token 调用真正的资源接口。一个精简后的授权地址大概是这样:https://login.example.com/authorize? response_type=code client_id=desktop-cli redirect_uri=http://127.0.0.1:8765/callback code_challenge=... code_challenge_method=S256 state=...这里最值得保留的不是 OAuth 参数表,而是两个边界:密码永远只输入到可信的系统浏览器里,CLI 只接收短命授权码;拿到授权码也不能直接换 token,还必须持有当前进程生成的 PKCE verifier。RFC 8252专门讨论原生应用授权,推荐用外部浏览器作为 user-agent,并要求公共原生客户端支持 PKCE。桌面应用使用 HTTP loopback redirect,也是规范明确支持的做法。webbrowser没有浏览器,它只是一个调度器Python 的webbrowser属于标准库,不负责下载网页,更不会在