0Pricing
C# Academy · 课时

刷新令牌与过期

实现安全的令牌续期。

刷新令牌与过期 是 CoddyKit 上的免费 C# Academy 课时。 这是第 4 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 C# Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 C# Academy 课程共包含 4 节课。

有效期问题

短时有效的访问令牌很安全,但使用起来不方便:每 15 分钟强制用户重新登录会带来糟糕的用户体验。

解决方案是使用刷新令牌——一种有效期更长的独立凭据,用于获取新的访问令牌,而无需重新输入密码。

// access token: 15 minutes
// refresh token: 7-30 days

什么是刷新令牌

刷新令牌通常是一个不透明的随机字符串(不是 JWT)。由于它的有效期较长,因此必须存储在服务器端,以便撤销。

请使用加密安全的 RNG 生成它。

public static string GenerateRefreshToken()
{
    var bytes = new byte[64];
    using var rng = RandomNumberGenerator.Create();
    rng.GetBytes(bytes);
    return Convert.ToBase64String(bytes);
}

存储刷新令牌

为每个刷新令牌持久化存储其所有者、有效期和撤销标志。这样就可以在用户注销或令牌被盗时使其失效。

public class RefreshToken
{
    public int Id { get; set; }
    public string Token { get; set; } = default!;
    public int UserId { get; set; }
    public DateTime ExpiresAt { get; set; }
    public bool IsRevoked { get; set; }
}

登录时签发两个令牌

登录成功后,返回短时有效的访问令牌和一个新的刷新令牌。将刷新令牌保存到数据库中。

var access = tokenService.CreateAccessToken(user);
var refresh = new RefreshToken
{
    Token = TokenService.GenerateRefreshToken(),
    UserId = user.Id,
    ExpiresAt = DateTime.UtcNow.AddDays(7)
};
db.RefreshTokens.Add(refresh);
await db.SaveChangesAsync();
return Results.Ok(new { access, refresh = refresh.Token });

刷新端点

专用的 /refresh 端点接受刷新令牌,并在令牌有效时签发全新的访问令牌。

app.MapPost("/refresh", async (RefreshDto dto, AppDb db, TokenService tokens) =>
{
    var stored = await db.RefreshTokens
        .SingleOrDefaultAsync(r => r.Token == dto.RefreshToken);

    if (stored is null || stored.IsRevoked ||
        stored.ExpiresAt < DateTime.UtcNow)
        return Results.Unauthorized();

    var user = await db.Users.FindAsync(stored.UserId);
    var access = tokens.CreateAccessToken(user!);
    return Results.Ok(new { access });
});

刷新令牌轮换

轮换可以强化整个流程:每次使用刷新令牌时,都撤销当前令牌并签发一个新的令牌。这样,被盗且已经使用过的令牌就会失效。

stored.IsRevoked = true;            // burn the old one
var next = new RefreshToken
{
    Token = TokenService.GenerateRefreshToken(),
    UserId = stored.UserId,
    ExpiresAt = DateTime.UtcNow.AddDays(7)
};
db.RefreshTokens.Add(next);
await db.SaveChangesAsync();

检测令牌重用

借助轮换机制,您可以检测令牌是否被盗:如果再次提交已经撤销的令牌,应将其视为安全漏洞,并撤销该用户的整个令牌家族。

if (stored.IsRevoked)
{
    // This token was already used - likely stolen.
    await RevokeAllUserTokens(stored.UserId, db);
    return Results.Unauthorized();
}

注销与撤销

注销只需撤销当前刷新令牌即可。访问令牌会在几分钟内自行过期。

app.MapPost("/logout", async (RefreshDto dto, AppDb db) =>
{
    var stored = await db.RefreshTokens
        .SingleOrDefaultAsync(r => r.Token == dto.RefreshToken);
    if (stored is not null) stored.IsRevoked = true;
    await db.SaveChangesAsync();
    return Results.Ok();
}).RequireAuthorization();

在客户端何处存储令牌

对于浏览器,最安全的方式是将刷新令牌存储在HttpOnly、Secure Cookie 中,使 JavaScript 无法读取它,从而降低 XSS 窃取的风险。

短时有效的访问令牌可以保存在内存中。

Response.Cookies.Append("refresh", refresh.Token, new CookieOptions
{
    HttpOnly = true,
    Secure = true,
    SameSite = SameSiteMode.Strict,
    Expires = refresh.ExpiresAt
});

清理已过期的令牌

刷新令牌会不断累积。请运行定期后台任务(例如托管服务),删除已过期或已撤销的行。

await db.RefreshTokens
    .Where(r => r.ExpiresAt < DateTime.UtcNow || r.IsRevoked)
    .ExecuteDeleteAsync();

选择有效期

在安全性和便利性之间取得平衡:

  • 访问令牌:5 到 15 分钟,限制令牌泄露后的暴露时间。
  • 刷新令牌:数小时到数周,具体取决于敏感程度。
  • 对于有效期超过一天的令牌,请使用轮换机制。
AccessTokenLifetime  = TimeSpan.FromMinutes(15);
RefreshTokenLifetime = TimeSpan.FromDays(7);

快速检查

测试您对刷新流程的理解。

回顾

您已经实现了刷新令牌流程:

  • 签发一个短时有效的访问令牌,以及一个较长、不可读、存储在服务器端的刷新令牌。
  • /refresh 端点使用有效的刷新令牌换取新的访问令牌。
  • 轮换和重用检测机制可以增强对令牌被盗的防护。
  • 将刷新令牌存储在 HttpOnly Cookie 中,并清理已过期的行。

JWT 认证课程到此完成。

常见问题解答

「刷新令牌与过期」课时是免费的吗?

是的 — 「刷新令牌与过期」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 C# Academy 课程的其余内容,请升级到 CoddyKit PRO。 C# Academy 课程共包含 4 节课。

「刷新令牌与过期」这节课中我会学到什么?

实现安全的令牌续期。 你通过在浏览器中直接运行的动手代码来练习 C# Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 C# Academy 需要有经验吗?

无需任何先前经验。CoddyKit 上的 C# Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 4 节课,共 4 节。

「刷新令牌与过期」课时需要多长时间?

大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。

我能在这节 C# Academy 课中编写并运行代码吗?

能。每节 C# Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。

此课程中的所有课时

  1. JWT 结构与声明
  2. 配置 JWT Bearer 身份验证
  3. 签发令牌
  4. 刷新令牌与过期
← 返回 C# Academy