Blazor 里 JWT 过期,用户正下单就被踢

ASP.NET Core Blazor编程系列: 使用JWT进行身份验证 头部包含了令牌的类型和所使用的算法,载荷包含了要传输的数据,签名用于验证令牌的完整性。通过以上步骤,我们成功实现了ASP.NET Core Blazor应用程序中的JWT身份验证。在登录时,我们将生成的JWT令牌设置为HTTP客户端的默认请求标头。在客户端的Blazor组件中,我们可以使用生成的JWT令牌进行身份验证。在上面的示例中,我们使用用户的ID和用户名创建了一组声明(Claims),设置了令牌的过期时间,并使用指定的密钥对令牌进行签名。在用户成功登录后,我们可以创建JWT令牌并将其返回给客户端。 阅读详情

用户在页面里填了一整页表单,点了提交——啪,跳回登录页。JWT 过期了,刷新令牌没接上,所有数据白填。这篇文章讲 Blazor 里怎么正确实现 JWT 刷新令牌,让用户无感续期。

先说为什么 Blazor 里这个问题特别恶心。

在普通 SPA(React/Vue)里,JWT 存在 localStorage,请求拦截器统一加 header,401 时自动刷新——一套 Axios 拦截器搞定。但 Blazor 不一样:Blazor Server 跑在服务端,Blazor WebAssembly 跑在浏览器里,两种模式下 token 的存储位置、刷新时机、信号传递方式完全不同。

而且 Blazor 的组件状态是活的——用户在页面上操作时,组件不会重新渲染,你没法靠"页面刷新"来触发重新认证。必须在 HTTP 层静默处理。

01 为什么 JWT 过期会"踢人"

JWT 有过期时间(exp claim)。过期后,API 服务器验证失败返回 401。如果你的应用不做刷新,401 的处理就是跳登录页。

问题是——JWT 的过期时间通常很短(15-30 分钟),这是安全设计。长过期时间 = token 被盗后攻击窗口大。所以业界做法是短 access token + 长 refresh token:

Access Token  — 15-30 分钟过期,放 Authorization header
Refresh Token — 7-30 天过期,存安全位置(httpOnly cookie / protected storage)
                    ↓ access token 过期时,用 refresh token 换新的

用户无感续期的流程是:

① 请求 API → 带 access token ② API 返回 401 → access token 过期了 ③ 拦截 401 → 用 refresh token 调 /refresh 端点换新 access token ④ 拿到新 token → 重放原始请求 ⑤ 用户完全无感,表单数据不丢

坑在哪?Blazor 的 HttpClient 不是浏览器 fetch,不能简单套 Axios 那套。Blazor Server 的 HttpClient 是 HttpClientFactory 创建的,Blazor WebAssembly 的 HttpClient 是 WASM runtime 里的——两者拦截 401 的方式完全不同。

02 Blazor Server:DelegatingHandler 拦截

Blazor Server 跑在服务端,HttpClient 可以套 DelegatingHandler——这是 .NET 原生的 HTTP 管道机制,所有请求经过 handler 链。

核心思路:自定义一个 AuthTokenHandler,在 SendAsync 里自动加 token,401 时自动刷新。

public class AuthTokenHandler : DelegatingHandler
{
    private readonly TokenService _tokenService;

    public AuthTokenHandler(TokenService tokenService)
    {
        _tokenService = tokenService;
    }

    protected override async Task<HttpResponseMessage> SendAsync(
        HttpRequestMessage request, CancellationToken ct)
    {
        // 1. 加 access token
        var token = await _tokenService.GetAccessTokenAsync();
        if (!string.IsNullOrEmpty(token))
            request.Headers.Authorization =
                new AuthenticationHeaderValue("Bearer", token);

        // 2. 发请求
        var response = await base.SendAsync(request, ct);

        // 3. 401 → 尝试刷新
        if (response.StatusCode == HttpStatusCode.Unauthorized)
        {
            var refreshed = await _tokenService
                .TryRefreshTokenAsync();
            if (refreshed)
            {
                // 4. 重放原始请求
                var newToken = await _tokenService
                    .GetAccessTokenAsync();
                request.Headers.Authorization =
                    new AuthenticationHeaderValue(
                        "Bearer", newToken);

                // 注意:HttpClient 会缓存请求,
                // 需要克隆一份再发
                response.Dispose();
                var retry = await CloneAndSendAsync(
                    request, ct);
                return retry;
            }
        }

        return response;
    }

    private async Task<HttpResponseMessage> CloneAndSendAsync(
        HttpRequestMessage req, CancellationToken ct)
    {
        var clone = new HttpRequestMessage(req.Method, req.RequestUri);
        // 克隆 content(如果有的话)
        if (req.Content != null)
        {
            var bytes = await req.Content.ReadAsByteArrayAsync(ct);
            clone.Content = new ByteArrayContent(bytes);
        }
        foreach (var h in req.Headers)
            clone.Headers.TryAddWithoutValidation(
                h.Key, h.Value);

        return await base.SendAsync(clone, ct);
    }
}

关键细节:

请求克隆——HttpRequestMessage 发送后不能复用,必须克隆一份再重发。这是最容易漏的一步,漏了直接报"请求已发送"异常。

并发刷新锁——多个请求同时 401 会触发多次刷新,refresh token 可能被消耗多次(如果是一次性 token)。加一个 SemaphoreSlim 保证只刷新一次,其他请求等结果。

刷新失败处理——refresh token 也过期了,跳登录页。但 Blazor Server 里不能直接 NavigationManager.NavigateTo("/login")(那是客户端导航),需要通过 JS Interop 调 location.href 做整页跳转。

// TokenService 里的并发刷新
private static readonly SemaphoreSlim _refreshLock = new(1, 1);

public async Task<bool> TryRefreshTokenAsync()
{
    await _refreshLock.WaitAsync();
    try
    {
        // 双重检查:也许别的线程刚刷过
        if (IsAccessTokenValid())
            return true;

        var refreshReq = new { RefreshToken = _refreshToken };
        var resp = await _httpClient.PostAsJsonAsync(
            "/api/auth/refresh", refreshReq);

        if (!resp.IsSuccessStatusCode)
        {
            // refresh token 也过期 → 强制登出
            await _jsRuntime.InvokeVoidAsync(
                "location.replace", "/login?expired=1");
            return false;
        }

        var tokens = await resp.Content
            .ReadFromJsonAsync<TokenResponse>();
        _accessToken = tokens.AccessToken;
        _refreshToken = tokens.RefreshToken;
        return true;
    }
    finally
    {
        _refreshLock.Release();
    }
}

03 Blazor WebAssembly:自定义 HttpMessageHandler

WASM 模式下思路一样,但实现有区别——token 存在浏览器里,而且没有 SemaphoreSlim 的跨组件同步问题(因为 WASM 是单线程的)。

存储选择:

// Program.cs — 注册带 token 拦截的 HttpClient
builder.Services.AddScoped<AuthTokenHandler>();
builder.Services.AddScoped(sp =>
{
    var handler = sp.GetRequiredService<AuthTokenHandler>();
    handler.InnerHandler = new HttpClientHandler();

    return new HttpClient(handler)
    {
        BaseAddress = new Uri(builder.HostEnvironment.BaseAddress)
    };
});

// Token 存 protected localStorage
// (Blazor WASM 的 ProtectedLocalStorage 在 Server 端,
//   WASM 用 IJSRuntime 直接调 localStorage API)
builder.Services.AddSingleton<ITokenStorage,
    LocalTokenStorage>();

WASM 里的 handler 和 Server 版几乎一样,区别在刷新失败时的跳转——WASM 可以直接用 NavigationManager 做客户端导航,不需要 JS Interop。

WASM 专属坑:localStorage 是异步的,但 DelegatingHandler.SendAsync 也是异步的,没问题。但如果你在 OnInitializedAsync 里调 API,刷新 + 重放的延迟会导致组件渲染两次——务必在组件里处理 Loading 状态,否则用户会看到一闪而过的错误。

04 两种模式都要注意的三件事

① refresh token 的存储位置

Blazor Server:存在服务端内存 / Session / Redis。别存 cookie——Blazor Server 用 SignalR 连接,cookie 跟着连接走,断线重连会丢。

Blazor WASM:存 localStorage。XSS 风险?WASM 默认不做 dangerouslySetInnerHTML,XSS 攻击面比传统 SPA 小。但如果你的 WASM 应用加载了第三方 JS 模块,仍有风险。折中方案:access token 存内存,refresh token 存 localStorage,JS 模块拿不到内存里的 access token。

② 刷新端点的设计

POST /api/auth/refresh
Body: { "refreshToken": "xxx" }
Response: {
    "accessToken": "新 access token",
    "refreshToken": "新 refresh token"  // 轮换!
}

refresh token 必须轮换——每次刷新后旧的失效,返回新的。不轮换 = refresh token 被盗后永久有效。进一步可以加 refresh token rotation + reuse detection:如果检测到旧 token 被使用,说明可能被窃取,立即吊销整个 token 家族。

③ 预刷新:别等 401 再刷

等 401 再刷的问题是——那个请求已经失败了。虽然重放能恢复,但用户可能看到一瞬间的错误状态。更好的做法是预判过期:在发请求前检查 access token 的 exp claim,如果快过期了(比如 5 分钟内),先刷新再发请求。

// TokenService 里加预判
public async Task<string> GetAccessTokenAsync()
{
    if (_accessToken != null)
    {
        var jwt = new JwtSecurityToken(_accessToken);
        // 过期前 5 分钟刷新
        if (jwt.ValidTo > DateTime.UtcNow.AddMinutes(5))
            return _accessToken;
    }

    // 快过期了 → 主动刷新
    await TryRefreshTokenAsync();
    return _accessToken;
}

这样 AuthTokenHandler 里 GetAccessTokenAsync 自带预判,401 分支只是兜底——正常情况下永远不会走到 401 分支。


Blazor JWT 刷新令牌,核心就四步: DelegatingHandler 拦截 → 401 自动刷新 → 请求重放 → 预判过期抢先刷 用户从头到尾无感,表单数据不丢。


收藏这篇,下次别再让用户填了一半被踢出去。 refresh token 接好,用户体验直接上一个台阶。

关注 CSharp精选营,每周二四 get 能直接抄的 C# 实战。

阅读原文:Blazor 里 JWT 过期,用户正下单就被踢 - 码录集

ASP.NET Core Blazor编程系列:JWT身份验证与登录 JWT(JSON Web Token)是一种流行的身份验证和授权机制,它允许客户端通过安全的方式向服务器进行身份验证,并在后续请求中使用令牌进行授权。我们首先配置了身份验证和授权服务,然后实现了用户登录请求的处理逻辑和生成JWT令牌的方法。通过使用JWT进行身份验证,我们可以构建安全、可靠的ASP.NET Core Blazor应用程序,并为用户提供良好的登录和授权体验。在上述代码中,我们创建了一个类似于登录表单的界面,包含用户名和密码的输入框以及一个登录按钮。的页面组件,只有经过身份验证的用户才能访问。 阅读详情

相关推荐

Blazor Server与JWT:双重身份验证的实践

本文介绍了在Blazor Server应用中同时实现Cookie和JWT双重身份验证的方法。首先配置基于Cookie的身份验证作为默认方案,然后添加JWT Bearer认证用于API访问。通过为API端点指定JWT认证方案,使移动应用能安全调用接口,同时保持Web浏览器的Cookie认证。这种混合方案既保障了Web会话安全,又满足了移动端API调用的认证需求,提高了应用的安全性和灵活性。

m0_62153576的博客 104

blazor-webassembly-jwt-authentication-example:为你的Web应用提供安全的身份认证方案

blazor-webassembly-jwt-authentication-example:为你的Web应用提供安全的身份认证方案 项目介绍 在现代Web应用开发中,身份认证是一个至关重要的环节。blazor-webassembly-jwt-authentication-example 是一个基于ASP.NET Core Blazor WebAssembly的JWT(JSON Web Tokens...

gitblog_00170的博客 1250

18、Blazor 中用户认证与授权的实现

本文详细介绍了如何在Blazor应用中实现自定义的JWT用户认证与授权机制,涵盖登录流程设计、认证状态提供程序构建、页面权限控制等核心步骤。同时探讨了该认证体系的优势,并进一步扩展了角色与策略管理、多因素认证及单点登录等高级功能的实现思路,帮助开发者构建安全、可扩展的Blazor应用。

ppp33的博客 88

关于JWT设置过期时间无效的问题

关于JWT设置过期时间无效的问题

cn_ljr的博客 3882

基于ASP.NET Core与Blazor WebAssembly的博客后台JWT认证与MySQL实践

现代Web应用普遍采用前后端分离架构,身份认证与授权是其中的核心环节。JWT(JSON Web Token)凭借无状态、跨域支持好、易于扩展等特性,成为分布式系统与前后端分离场景下的主流认证方案。通过服务端签发令牌、客户端存储并按请求附加令牌,再配合后端中间件校验签名与有效期,即可构建一套完整的安全链路。在技术落地中,Blazor WebAssembly作为运行在浏览器端的.NET前端框架,能够复用C#技能栈,与WebApi配合实现页面交互与接口调用;而MySQL作为成熟的关系型数据库,配合EF Core

weixin_33393017的博客 255

FreeSWITCH视频通话实战:关键配置文件解析与编解码优化

本文详细解析了FreeSWITCH视频通话实战中的关键配置,重点介绍了如何通过修改`conf/vars.xml`和`sip_profiles/internal.xml`文件来启用媒体代理、优化编解码器设置(如H.264和VP8),并解决常见的视频流协商与网络穿透问题,帮助用户快速实现稳定、高质量的视频通话功能。

js777的博客 256

.NETCore Blazor使用localStorage存储登录信息

以上代码展示了如何通过 JWT 实现用户登录、读取、修改和删除令牌的功能。通过将令牌存储在或中,可以实现无状态的用户认证,并在每次请求中附加令牌进行身份验证。

AngelCryToo的专栏 1354

告别Win11睡眠假死:深入解析Modern Standby S0与S3冲突及注册表修复方案

本文深入解析了Windows 11中Modern Standby(S0)与传统睡眠(S3)模式的冲突,该冲突是导致电脑睡眠后出现假死、断网等问题的根源。文章提供了通过修改注册表键值(PlatformAoAcOverride)强制启用稳定S3睡眠的终极修复方案,并附有详细诊断步骤与避坑指南,帮助用户彻底解决睡眠故障。

ol789012的博客 823

jwt token 过期刷新_JWT颁发以及权限校验实践.net core

《权限设计》关于权限设计的一些方案,这里是使用.net core来实现jwt的授权验证,为了方便平时快速接入,开箱即用。jwt有token发行端(JwtSecurityTokenExtension)和接收端验证(PermissionsControl)两块内容,Github源码。Jwt Token发行端有时候只是简单用JWT没必要上Identity4,杀鸡焉用宅牛刀,JwtSecurityToken...

weixin_39982452的博客 869

专治疑难系列 - 解决打印机凭证冲突问题

一、问题描述 二、解决方法 三、问题已解决

Passerby_Wang的博客 2万+

声品质粗糙度matlab,声品质的应用分析方法

声品质的应用分析方法2016-04-05 09:18:57阅读次数:14198摘要:声品质分析在噪声的主观评价方面已经得到越来越多的应用。本文比较了声品质分析与传统计权声级的区别,并介绍了在声品质分析的实际应用中,针对稳态信号、非稳态信号的几种不同分析方法,以及各分析方法的要求和特点。关键词:声品质,响度,尖锐度,粗糙度,波动度1前言传统评价噪声的方法主要为计权声压级,用以反映声音的大小。但是人耳...

weixin_30767323的博客 2438

使用 Blazor 开发内部后台(三):登录

James: 《使用Blazor开发内部后台》系列是技术社区中一位朋友投稿的系列文章,介绍自己为公司的 WebForm 遗留系统使用 Blazor 重写前端 UI 的经历。本文为第三篇,如...

dotNET跨平台 6246

小论文/大论文必备 | RT-DETR目标检测、数据集增强 | 引入多种数据集增强方法,支持图像和标签同步扩充增强,助力小论文和大论文实验涨点策略,平均提升模型mAP约1-2个百分点

RT-DETR目标检测数据增强策略研究 ,本文针对RT-DETR目标检测模型提出9种数据增强方法,包括几何变换(水平/垂直翻转、中心裁剪)、光照调整(亮度、对比度)和噪声添加(高斯/椒盐噪声)等。所有增强操作均保持图像与标签同步变换,确保训练数据的准确性。实验表明,该策略可提升模型mAP 1-2个百分点,对小目标检测效果尤为显著。文中提供了完整的Python实现代码,支持批量处理图像和标签文件,并详细说明了各增强方法的功能特点。该方法通过提升数据多样性,有效增强了模型在复杂场景下的鲁棒性和泛化能力。

Ai缝合怪、助力小伙伴高效发论文 460

jwt token 过期刷新_初识JWT(Json Web Tokens) 认证一二三

1.什么是JWT Token  JWT(Json Web Tokens) 是一个开放标准(RFC 7519),它定义了一种简洁,自包含,JSON 对象形式的安全传递信息的方法。JWT常用在 Web 应用或者移动应用上,Token是令牌的意思,表示只有拿着令牌才具有一些权限。JWT的声明(Claim)一般被用来在身份提供者和服务提供者间传递身份验证信息,也可以增加一些额外的其它业务逻辑所必须的声明信...

weixin_39935654的博客 659

英飞凌TC3xx之一起认识GTM(八)如何使用DTM实现死区时间配置

本文简要介绍英飞凌TC3xx系列芯片的DTM模块结构,以及有哪些相关寄存器可用于实现相关配置。

无所适从的我的博客 4650

如何为 Claude Code 配置代理与网络环境

那么大概率不是软件问题,而是。因为 Claude Code 是运行在终端里的,不是浏览器。

sg_knight的专栏 3480

学习ASP.NET Core Blazor编程系列二十七——JWT登录(1)

JWT只是缩写,全称则是JSON Web Tokens,是目前流行的跨域认证解决方案,是基于开放标准RFC7519,提供一种身份认证与信息交换的解决方案,是一种基于JSON的用于在网络上声明某种主张的令牌(token)。由于http的连接是状态的特性,server端和client是不会记住每个请求是谁发过来的,也不会知道当前发送请求的用户是否已经对过身份认证,如果用户的每一个请求,都要与数据库通讯进行身份认证,会增加server和数据库的成本。

Gefangenes的博客 1165

试读源码在这里下载

试读文章的源码在这里下载。源码不做任何修改,重点重点重点:为了代码运行不报错,安装matlab 版本为 2021 及以上版本。matlab安装教程大家可以参考这个教程:手把手教你安装matlab软件。

在职AI算法工程师,擅长计算机视觉,YOLO目标检测、分割等,擅长web、pyqt界面可视化,好内容持续更新中,来这里跟大家一起学习,共同进步 4302

Blazor .NET 8 与 GraphQL 集成:JWT 认证全流程实战指南

在前后端分离与微服务架构日益普及的今天,API 的安全认证设计成为开发者必须直面的基础工程问题。JWT(JSON Web Token)作为一种无状态、跨域友好的身份认证机制,通常被用于保护 REST API,但当其与 GraphQL 这样的查询语言结合时,认证逻辑需要下沉到字段解析层级。HotChocolate 作为 .NET 生态中成熟的 GraphQL 服务端框架,通过 @authorize 指令与 ASP.NET Core 授权策略无缝衔接,为精细化权限控制提供了理论支撑。在实际业务系统中,无论是内部

weixin_33290540的博客 330

LinePhone3.2.7(android端最新版本) sip客户端

SIP客户端For android:LinePhone3.2.7(最新版本),官网地址:http://www.linphone.org/

假人有限元模型

假人模型,车辆碰撞假人有限元模型,适合做乘员安全的研究者利用

Blazor JWT登录退出身份控制定时检测账户管理示例项目

Blazor JWT登录退出身份控制定时检测账户管理示例项目 去发现同类优质开源项目:https://gitcode.com/ 本示例项目为基于.Net Core 7.04的Blazor Server版本,主要面向企业内部账户分发的应用程序开发。该项目集成了身份控制、定时检测和账户管理等功能,旨在帮助开发者快速掌握相关技术。 项目功能 身份控制:本项目适用于非开放公众注册的企业内部应用。账户初...

gitblog_06705的博客 451

文档:亲测可用解决vnc灰屏,黑屏,鼠标大黑叉情况

主要解决vnc-viewer灰屏,黑屏,鼠标大黑叉等现象,详细见文档。

学习ASP.NET Core Blazor编程系列二十六——登录(5)

既然是抽象类,我们需要自定义一个它的子类,由于是模拟登录,进行登录流程的验证,因此我们先来做一个测试的Provider来试试。在webapi出现之后,出现了JWT这样的认证方式,原理大同小异,相同的是, 认证信息都是保存在请求头中传递的,不同是JWT中的认证信息需要编码写入请求头之后再发送请求,不像浏览器,发送请求时会自动带上cookie信息,不需要编码。现在我们已经完成了登录认证的Provider了,接下來要做的事情,就是让我们的页面上的组件,可以获取登录信息,来决定是登录用户是否已经授权。

Gefangenes的博客 2326

NTscan扫描工具

ntscan是一个扫描器,可以扫描没有密码和弱密码的共享,先到配置文件中填写猜测的用户名和密码,扫描过程中右侧出现的是扫描日志。

Blazor客户端认证示例项目推荐

Blazor客户端认证示例项目推荐 1. 项目基础介绍与主要编程语言 本项目是开源技术专家Chris Sainty的Blazor客户端认证示例项目,旨在展示如何在客户端Blazor应用程序中实现与WebAPI及ASP.NET Core Identity的集成认证。主要编程语言为C#,同时涉及HTML和CSS以构建用户界面。 2. 项目的核心功能 项目的核心功能是提供一个完整的示例,演示如何使用客户...

gitblog_00388的博客 543

Blazor.Auth:项目的核心功能/场景

Blazor.Auth:项目的核心功能/场景 简化Blazor认证流程,支持JWT及自定义认证方案 项目介绍 在现代化Web应用程序开发中,认证功能是不可或缺的一环。Blazor.Auth开源项目旨在为Blazor开发者提供一种简单、高效的认证解决方案。该库无缝集成Blazor框架,并基于JWT(JSON Web Tokens)提供了自定义认证流程的支持,让开发者能够轻松实现用户身份验证和状态持久...

gitblog_00187的博客 637

Net6 JWT 与 Blaozor登录认证未授权跳转注册界面

一、WebApi配置JWT认证 1、NuGet安装引用 Microsoft.AspNetCore.Authentication.JwtBearer 2、API增加认证[Authorize] 给Controller一个方法增加认证访问。 3、添加认证服务 builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme) .AddJwtBearer(options =>...

873149745 3366

学习ASP.NET Core Blazor编程系列二十八——JWT登录(2)

令牌

Gefangenes的博客 701
上一篇: IIS 后面挂 Kestrel,这 3 个配置错了就 502
下一篇: 两个请求同时改库存,RowVersion 救了一命
码农刚子.
博客等级 码龄8年 554粉丝 128原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

码农刚子.

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值