You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何为打包为Electron桌面应用的Blazor Server创建获取JWT的登录页

可行实现方案

下面直接给两个可落地的方案,优先推荐第一种,适配Electron场景成本最低:

方案1:静态登录页 + 手动启动Blazor SignalR连接(推荐)

实现步骤

  • 第一步:在wwwroot目录下新增login.html作为登录入口,Electron启动时默认加载这个页面
<!-- wwwroot/login.html 核心代码 -->
<body>
    <div>
        <input type="text" id="username" placeholder="账号">
        <input type="password" id="password" placeholder="密码">
        <button onclick="login()">登录</button>
        <span id="errMsg" style="color:red"></span>
    </div>
    <script>
        async function login() {
            const username = document.getElementById('username').value
            const password = document.getElementById('password').value
            try {
                // 调用远端JWT签发接口拿令牌
                const resp = await fetch('你的JWT签发服务地址', {
                    method: 'POST',
                    headers: {'Content-Type': 'application/json'},
                    body: JSON.stringify({username, password})
                })
                if (!resp.ok) throw new Error('账号或密码错误')
                const {accessToken} = await resp.json()
                // 存到LocalStorage方便后续刷新等操作使用
                localStorage.setItem('access_token', accessToken)
                // 跳转到Blazor宿主页
                location.href = '/index.html'
            } catch (e) {
                document.getElementById('errMsg').innerText = e.message
            }
        }
    </script>
</body>
  • 第二步:修改Blazor宿主页(默认是Pages/_Host.cshtml或者wwwroot/index.html),禁用blazor.server.js自动启动,手动启动时携带JWT
<!-- 引用blazor.server.js时关闭自动启动 -->
<script src="_framework/blazor.server.js" autostart="false"></script>
<script>
    document.addEventListener('DOMContentLoaded', async () => {
        const accessToken = localStorage.getItem('access_token')
        // 没有令牌直接退回登录页
        if (!accessToken) {
            location.href = '/login.html'
            return
        }
        // 手动启动Blazor,配置SignalR连接参数,把JWT放在查询参数
        await Blazor.start({
            configureSignalR: function (builder) {
                builder.withUrl('/_blazor', {
                    accessTokenFactory: () => accessToken
                })
            }
        })
    })
</script>
  • 第三步:调整你之前写的JwtBearer配置,去掉硬编码的令牌,优先取SignalR带过来的令牌
options.Events = new JwtBearerEvents
{
    OnMessageReceived = context =>
    {
        // SignalR默认会把accessTokenFactory返回的令牌放在access_token查询参数
        var accessToken = context.Request.Query["access_token"];
        // 也兼容从Authorization头取,适配其他HTTP接口调用
        if(string.IsNullOrEmpty(accessToken) && context.Request.Headers.ContainsKey("Authorization"))
        {
            accessToken = context.Request.Headers["Authorization"].ToString().Replace("Bearer ", "");
        }
        context.Token = accessToken;
        return Task.CompletedTask;
    }
};
  • 第四步:在Program.cs/Startup.cs里配置静态文件路由,确保login.html能被正常访问,不需要认证即可访问
// 放在认证中间件之前
app.UseStaticFiles();
// 配置login.html允许匿名访问
app.UseWhen(context => context.Request.Path.StartsWithSegments("/login.html"), appBuilder =>
{
    appBuilder.Use(async (context, next) =>
    {
        await next();
    });
});

方案2:Blazor内置登录组件 + Circuit绑定令牌

如果不想做单独的静态登录页,可以直接在Blazor里做登录组件,步骤如下:

  • 全局取消默认的认证拦截,允许未认证用户访问Blazor应用
  • 首页加判断,未认证时渲染登录组件,用户输入账号密码后调用JWT接口拿到令牌
  • 拿到令牌后调用NavigationManager.NavigateTo("/?access_token=" + token, forceLoad: true),强制重载页面,把令牌放在查询参数里
  • OnMessageReceived事件里优先取查询参数的令牌,逻辑和方案1一致

之前Razor Pages方案无法落地的问题修复

如果要继续用你之前的Razor Pages登录方案,只需要补充两个配置即可:

  1. 在服务注册时加services.AddRazorPages();
  2. 在中间件配置里加app.MapRazorPages();放在Blazor路由配置之前,Razor页面就能正常访问了。

内容的提问来源于stack exchange,提问作者tinmac

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.05 09:06:01