Tauri 项目实践:客户端与 Web 端的授权登录实现方案
在跨平台应用开发中(如基于 Tauri 构建的 Mind Elixir 客户端),如何让应用从 Web 端顺畅地获取授权并完成登录往往是一个常见且重要的需求。本文将总结我们在这个 Tauri 项目中探索的两种登录实现方法,并分享一个在 macOS 上开发时遇到的非常经典的坑点。 在项目最初,为了解决 Web 端把 Token 传回桌面端的痛点,我们采取了在本地启动 HTTP 服务器进行跨应用通信的方法: 通过 Tauri 结合 Rust 的 接下来,React 前端监听这个全局事件,获取 Token 存入本地存储后即可完成登录: 由于本地服务器面临上述潜在风险,并且不符合系统深层集成的新趋势,我们后续改用了更加优雅和原生的方案——自定义 Scheme 登录(如唤起 mind-elixir://)。 引入插件和配置: 注:移动端配置生效同时依赖同步写入 Android 的 桌面系统唤醒支持: 前端接收请求: 利用这种方式,用户在使用浏览器验证登陆态后,浏览器能顺滑提示是否打开目标应用,体验极佳。 根据 Tauri 官方文档说明,在 macOS 和 Linux 系统下,Deep Link(自定义 Scheme)在开发模式( 如果你修改了基于 Scheme 登录的代码,请务必将其打包后(旧的登录方式:本地 HTTP Server 通信(遗留方案)
实现原理
axum 框架,桌面程序会在后台启动一个微型的本地服务器,监听特定端口(如 127.0.0.1:6595)。当用户在浏览器(如 cloud.mind-elixir.com)中登录完毕后,Web 页面直接向这个本地接口发出带上登录参数的 POST 请求:// axum_router.rs
async fn login_handler(
headers: HeaderMap,
Query(params): Query<Params>,
handle_clone: tauri::AppHandle,
) -> impl IntoResponse {
let token = params.token;
// 收到 HTTP 请求后,向 Tauri 的前端触发全局 login 事件
let _ = handle_clone.emit("login", Login { token: token });
// ...处理 CORS 返回
}// App.tsx
const unlisten = listen<{ token: string }>('login', async (e) => {
localStorage.setItem('token', e.payload.token)
await fetchData()
toast.success('登录成功')
})优缺点
tauri dev)下随意调试,无需进行系统级的协议注册。新的登录方式:自定义 Scheme / Deep Link
配置与实现
启用 @tauri-apps/plugin-deep-link 插件,并在 tauri.conf.json 下注册我们的特定协议头部 mind-elixir:"plugins": {
"deep-link": {
// 移动端(iOS/Android)配置
"mobile": [
{
"scheme": ["mind-elixir"],
"appLink": false
}
],
// 桌面端配置
"desktop": {
"schemes": ["mind-elixir"]
}
}
}AndroidManifest.xml (<data android:scheme="mind-elixir" />) 与 iOS 的 Info.plist (CFBundleURLSchemes) 中。
在 src-tauri/src/lib.rs 的初始化钩子处,我们需要给 Windows 和 Linux 用户调用显式的注册 API。#[cfg(any(windows, target_os = "linux"))]
{
use tauri_plugin_deep_link::DeepLinkExt;
app.deep_link().register_all()?;
}
在收到协议请求(即网页重定向到了形如 mind-elixir://login?token=xxxx 的长链接)时,使用 Tauri 的 API 解析深层链接并完成授权。既要负责冷启动阶段获取(getCurrent()),也要监控运行时唤醒(onOpenUrl):import { onOpenUrl, getCurrent } from '@tauri-apps/plugin-deep-link'
import { getCurrentWindow } from '@tauri-apps/api/window'
import { isMobile } from './utils/platform' // 项目中自定义的环境判断工具
const handleDeepLinkUrls = async (urls: string[]) => {
if (!urls || urls.length === 0) return
// 【各端表现差异处理】
// 移动端(尤其是 iOS/Android)点击 Deep Link 浏览器会自动切换/唤醒对应的 App 到前台。
// 但在桌面端接收到 deep link 事件后,应用窗口可能依然保持在后台,因此我们需要通过 window API 手动将其调出并聚焦。
if (!isMobile()) {
const win = getCurrentWindow()
await win.show()
await win.setFocus()
}
// 检查数组中以特定协议开头的链接
const loginUrl = urls.find((url) => url.startsWith('mind-elixir://login'))
if (loginUrl) {
const url = new URL(loginUrl)
const token = url.searchParams.get('token')
if (token) {
localStorage.setItem('token', token)
await fetchData()
toast.success('登录成功')
}
}
}
// 处理冷启动
getCurrent().then((urls) => {
if (urls) handleDeepLinkUrls(urls)
})
// 处理运行时被协议唤醒
onOpenUrl(handleDeepLinkUrls)避坑指南:macOS/Linux 的自定义 Scheme 调试限制
tauri dev)下是无法正常工作的。tauri build)运行该程序来进行测试。这同时也体现了第一种 HTTP 通信方案的一个优势——它可以在不用频繁打包的开发阶段充当最佳的调试通道。原文链接