在 .NET 8.0 中实现 JWT 刷新令牌

介绍

在 Web 开发领域,安全是重中之重。JSON Web Tokens (JWT) 已成为在各方之间安全传输信息的热门选择。然而,在 JWT 过期后,如何维护用户会话并避免频繁登录至关重要。这正是 JWT 刷新令牌应运而生的地方。

在本文中,我们将指导您在 .NET 8.0 环境中实现 JWT 刷新令牌。我们将通过完整的示例介绍每个步骤,以确保清晰地理解整个过程。

JWT 和刷新令牌

JSON Web Tokens (JWT) 由三部分组成:标头、有效负载和签名。它们经过数字签名以验证其真实性,并包含声明,这些声明是关于实体(用户)和其他数据的声明。JWT 具有到期时间 (exp),到期后将被视为无效。刷新令牌用于在原始令牌到期后获取新的 JWT,而无需用户重新输入其凭据。

设置.NET项目

让我们使用 JWT 和刷新令牌创建一个简单的身份验证系统。

首先,确保您已安装必要的包(System.IdentityModel.Tokens.Jwt 和 Microsoft.AspNetCore.Authentication.JwtBearer)。

模型

创建两个模型来表示登录请求和包含令牌的响应。

// LoginModel.cs
public class LoginModel
{
public string Username { get; set; }
public string Password { get; set; }
}

// TokenResponse.cs
public class TokenResponse
{
public string AccessToken { get; set; }
public string RefreshToken { get; set; }
}

授权控制器

创建一个负责处理身份验证和令牌生成的 AuthController。

[ApiController]
[Route("[controller]")]
public class AuthController : ControllerBase
{
private readonly IConfiguration _config;
private readonly IUserService _userService;

    public AuthController(IConfiguration config, IUserService userService)
{
_config = config;
_userService = userService;
}

    [HttpPost("login")]
public IActionResult Login(LoginModel loginModel)
{
// Authenticate user
var user = _userService.Authenticate(loginModel.Username, loginModel.Password);

        if (user == null)
return Unauthorized();

        // Generate tokens
var accessToken = TokenUtils.GenerateAccessToken(user, _config["Jwt:Secret"]);
var refreshToken = TokenUtils.GenerateRefreshToken();

        // Save refresh token (for demo purposes, this might be stored securely in a database)
// _userService.SaveRefreshToken(user.Id, refreshToken);

        var response = new TokenResponse
{
AccessToken = accessToken,
RefreshToken = refreshToken
};

        return Ok(response);
}

    [HttpPost("refresh")]
public IActionResult Refresh(TokenResponse tokenResponse)
{
// For simplicity, assume the refresh token is valid and stored securely
// var storedRefreshToken = _userService.GetRefreshToken(userId);

        // Verify refresh token (validate against the stored token)
// if (storedRefreshToken != tokenResponse.RefreshToken)
//    return Unauthorized();

        // For demonstration, let's just generate a new access token
var newAccessToken = TokenUtils.GenerateAccessTokenFromRefreshToken(tokenResponse.RefreshToken, _config["Jwt:Secret"]);

        var response = new TokenResponse
{
AccessToken = newAccessToken,
RefreshToken = tokenResponse.RefreshToken // Return the same refresh token
};

        return Ok(response);
}
}

Token Utility

创建一个实用程序类 TokenUtils 来处理令牌的生成和验证。

public static class TokenUtils
{
public static string GenerateAccessToken(User user, string secret)
{
var tokenHandler = new JwtSecurityTokenHandler();
var key = Encoding.ASCII.GetBytes(secret);

        var tokenDescriptor = new SecurityTokenDescriptor
{
Subject = new ClaimsIdentity(new[] { new Claim("id", user.Id.ToString()) }),
Expires = DateTime.UtcNow.AddMinutes(15), // Token expiration time
SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature)
};

        var token = tokenHandler.CreateToken(tokenDescriptor);
return tokenHandler.WriteToken(token);
}

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

    public static string GenerateAccessTokenFromRefreshToken(string refreshToken, string secret)
{
// Implement logic to generate a new access token from the refresh token
// Verify the refresh token and extract necessary information (e.g., user ID)
// Then generate a new access token

        // For demonstration purposes, return a new token with an extended expiry
var tokenHandler = new JwtSecurityTokenHandler();
var key = Encoding.ASCII.GetBytes(secret);

        var tokenDescriptor = new SecurityTokenDescriptor
{
Expires = DateTime.UtcNow.AddMinutes(15), // Extend expiration time
SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature)
};

        var token = tokenHandler.CreateToken(tokenDescriptor);
return tokenHandler.WriteToken(token);
}
}

用户服务(示例)

为了演示目的,这里有一个提供用户身份验证的简单 UserService。

public interface IUserService
{
User Authenticate(string username, string password);
// void SaveRefreshToken(int userId, string refreshToken);
// string GetRefreshToken(int userId);
}

public class UserService : IUserService
{
private readonly List<User> _users = new List<User>
{
new User { Id = 1, Username = "user1", Password = "password1" }
};

    public User Authenticate(string username, string password)
{
var user = _users.SingleOrDefault(x => x.Username == username && x.Password == password);
return user;
}

    // For demo purposes - methods to save and retrieve refresh tokens
}

用户模型(示例)

创建一个简单的用户模型。

public class User
{
public int Id { get; set; }
public string Username { get; set; }
public string Password { get; set; }
}

启动配置

在您的 Startup.cs 中,配置 JWT 身份验证。

public void ConfigureServices(IServiceCollection services)
{
// ...

    var secret = Configuration["Jwt:Secret"];
var key = Encoding.ASCII.GetBytes(secret);

    services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = false,
ValidateAudience = false,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
IssuerSigningKey = new SymmetricSecurityKey(key)
};
});

    // ...
}

重要提示

这是一个用于演示的基本实现。在生产环境中,您应该增强安全性,安全地处理令牌存储,并实现适当的验证和错误处理。
为了更好的安全性,请考虑使用 IdentityServer4 库或其他成熟的身份验证解决方案。

结论

在 .NET 8.0 中实现 JWT 刷新令牌涉及配置身份验证中间件、在身份验证时生成令牌以及根据需要刷新过期令牌。此过程允许无缝令牌更新,而无需用户重复登录,从而增强了安全性。

记住要安全地处理令牌存储并实施适当的验证逻辑,以确保身份验证系统的安全性和完整性。

如果您喜欢此文章,请收藏、点赞、评论,谢谢,祝您快乐每一天。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。
如若转载,请注明出处:http://www.pswp.cn/diannao/97183.shtml
繁体地址,请注明出处:http://hk.pswp.cn/diannao/97183.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

深入解析 git push 命令

1. 基础语法 git push 的基本语法如下: git push <远程仓库名> <本地分支名>:<远程分支名> [选项]<远程仓库名>: 通常是 origin(默认的远程仓库名称)。 <本地分支名>:<远程分支名>: 指定要推送的本地分支以及目标远程分支。如果省略远…

UI弹出动画

简介的UI弹出动画 使用方式很简单 挂载到需要弹出的目标 即可 using UnityEngine; using DG.Tweening; using Unity.VisualScripting;/// <summary>/// 简洁的UI动画脚本/// 直接挂载到UI组件上&#xff0c;调用Play()播放缩放弹出动画/// </summary>public class …

PostgreSQL诊断系列(6/6):配置项全景解析——打造你的专属优化清单

&#x1f517; 作为《PostgreSQL诊断系列》的收官之作&#xff0c;今天我们系统梳理 postgresql.conf 中的核心参数&#xff0c;将前5篇的“诊断”转化为“调优”&#xff0c;打造一套生产环境专属的配置模板。 你是否&#xff1a; 不知道哪些参数该调&#xff1f;害怕调错导致…

Flink Slot 不足导致任务Pending修复方案

当前有3个虚拟机节点&#xff0c;每个节点配置的slot节点数量是4&#xff0c;${FLINK_HOME}/conf/flink-conf.yaml 关于slot的配置如下&#xff1a; # The number of task slots that each TaskManager offers. Each slot runs one parallel pipeline. taskmanager.numberOfTas…

亚马逊合规风控升级:详情页排查与多账号运营安全构建

2025年亚马逊掀起的大规模扫号行动&#xff0c;聚焦商品详情页合规性审查&#xff0c;标志着跨境电商合规监管进入严风控时代&#xff0c;此次行动以关键词规范与定价诚信为核心&#xff0c;大量卖家因内容违规遭遇账号停用&#xff0c;对于卖家而言&#xff0c;构建系统化的合…

FISCO-BCOS-Python 模板

基于Python-SDK的FISCO BCOS区块链HelloWorld模板&#xff0c;提供了简单的问候语设置和查询功能。本项目采用现代Python开发实践&#xff0c;包含完整的配置管理、测试框架和项目结构。 快速开始 仓库地址&#xff1a;git clone https://gitee.com/atanycosts/python-fisco-te…

移动端(微信等)使用 vConsole调试console

本文介绍了一种在移动端真机上进行调试的方法——使用VConsole。通过简单的安装步骤和代码配置&#xff0c;开发者可以在移动端直接查看console.log输出&#xff0c;极大提升了调试效率。 摘要生成于 C知道 &#xff0c;由 DeepSeek-R1 满血版支持&#xff0c; 前往体验 >作…

云计算资源分配问题

这里写目录标题一、云计算资源的基本类型二、资源分配的目标三、资源分配的方式四、资源分配的技术与工具五、挑战与优化方向六、实际应用场景举例总结云计算资源分配是指在云计算环境中&#xff0c;根据用户需求、应用程序性能要求以及系统整体效率&#xff0c;将计算、存储、…

深度学习之第二课PyTorch与CUDA的安装

目录 简介 一、PyTorch 与 CUDA 的核心作用 1.PyTorch 2.CUDA 二、CUDA的安装 1.查看 2.下载安装 3.检查是否安装成功 三、PyTorch的安装 1.GPU版本安装 2.CPU版本安装 简介 在深度学习的实践旅程中&#xff0c;搭建稳定且高效的开发环境是一切实验与项目的基础&…

Ubuntu22.04 安装和使用标注工具labelImg

文章目录一、LabelImg 的安装及配置1. 安装2. 配置二、使用1. 基础操作介绍2. 创建自定义标签2.1 修改 predefined_classes.txt2.2 直接软件界面新增3. 图像标注3.1 重命名排序3.2 标注3.2 voc2yolo 格式转换3.3 视频转图片Yolo系列 —— Ubuntu 安装和使用标注工具 labelImgYo…

Jenkins与Docker搭建CI/CD流水线实战指南 (自动化测试与部署)

更多云服务器知识&#xff0c;尽在hostol.com你是否已经厌倦了那个“人肉”部署的重复循环&#xff1f;每一次 git push 之后&#xff0c;都像是一个庄严的仪式&#xff0c;你必须虔诚地打开SSH&#xff0c;小心翼翼地敲下一连串的 git pull, npm install, docker build, docke…

【数据可视化-100】使用 Pyecharts 绘制人口迁徙图:步骤与数据组织形式

&#x1f9d1; 博主简介&#xff1a;曾任某智慧城市类企业算法总监&#xff0c;目前在美国市场的物流公司从事高级算法工程师一职&#xff0c;深耕人工智能领域&#xff0c;精通python数据挖掘、可视化、机器学习等&#xff0c;发表过AI相关的专利并多次在AI类比赛中获奖。CSDN…

5G相对于4G网络的优化对比

5G网络作为新一代移动通信技术&#xff0c;相比4G实现了全方位的性能提升和架构优化。5G通过高速率、低时延和大连接三大核心特性&#xff0c;有效解决了4G网络面临的数据流量爆炸式增长和物联网应用瓶颈问题 &#xff0c;同时引入了动态频谱共享、网络切片等创新技术&#xff…

AR智能巡检:智慧工地的高效安全新引擎

在建筑行业,工地安全管理与施工效率的提升一直是核心议题。随着增强现实(AR)技术的快速发展,AR智能巡检系统正逐步成为智慧工地的“标配”,通过虚实结合、实时交互和智能分析,推动建筑行业迈入数字化、智能化的新阶段。本文将从技术原理、应用场景、核心优势及未来趋势等…

TypeScript:枚举类型

1. 什么是枚举类型&#xff1f;枚举&#xff08;Enum&#xff09;是TypeScript中一种特殊的数据类型&#xff0c;用于定义一组命名的常量值。它允许开发者用一个友好的名称来代表数值或字符串&#xff0c;避免使用“魔法数字”或硬编码值。基本语法&#xff1a;enum Direction …

Maven 编译打包一个比较有趣的问题

前言最近做项目&#xff0c;发现一个比较有意思的问题&#xff0c;其实发现了问题的根源还是很好理解&#xff0c;但是如果突然看到会非常的难以理解。在Java项目中&#xff0c;明明包名错误了&#xff0c;居然可以正常编译打包&#xff0c;IDEA报错了&#xff0c;但是mvn命令正…

Leetcode贪心算法

题目&#xff1a;划分字母区间 题号&#xff1a;763class Solution {public List<Integer> partitionLabels(String s) {List<Integer> list new LinkedList();int[] edge new int[27];char[] chars s.toCharArray();for(int i 0; i <chars.length;i){edge…

【密码学基础】加密消息语法 CMS:给数字信息装个 “安全保险箱”

如果说数字世界是一座繁忙的城市&#xff0c;那么我们每天发送的邮件、合同、软件安装包就是穿梭在城市里的 “包裹”。有些包裹里装着隐私&#xff08;比如银行账单&#xff09;&#xff0c;有些装着重要承诺&#xff08;比如电子合同&#xff09;&#xff0c;还有些关系到设备…

leetcode算法刷题的第二十天

1.leetcode 39.组合总和 题目链接 这道题里面的数组里面的数字是可以重复使用的&#xff0c;那可能就会有人想&#xff0c;出现了0怎么办&#xff0c;有这个想法的很好&#xff0c;但是题目要求数组里面的数字最小值为1&#xff0c;这就可以让人放心了。但是有总和的限制&…

使用Spoon报错Driver class ‘com.microsoft.sqlserver.jdbc.SQLServerDriver‘ could not be found解决方法

使用Spoon报错Driver class ‘com.microsoft.sqlserver.jdbc.SQLServerDriver’ could not be found 产生原因 出现这个错误是因为Spoon无法找到用于连接MS SQL Server的JDBC驱动程序。该驱动程序是一个jar文件,通常需要手动下载并配置。 解决方案 下载JDBC驱动程序: 访问 M…