当前位置: 首页 > news >正文

.NET Core 中生成 JWT(JSON Web Token)

实现说明

  1. 核心依赖

    • 需要安装 NuGet 包:System.IdentityModel.Tokens.Jwt 和 Microsoft.AspNetCore.Authentication.JwtBearer
  2. 关键组件

    • JwtSettings:存储 JWT 配置(密钥、发行人、受众、过期时间等)
    • JwtHelper:封装 JWT 生成和验证的核心逻辑
    • 服务注册:在 Program.cs 中配置 JWT 认证服务
    • 示例控制器:展示如何生成令牌和使用令牌访问受保护资源
  3. 使用流程

    • 客户端发送登录请求(用户名 / 密码)
    • 服务器验证成功后生成 JWT 令牌并返回
    • 客户端后续请求在 HTTP 头部携带 Authorization: Bearer {token}
    • 服务器验证令牌有效性并授权访问
  4. 安全注意事项

    • 密钥(SecretKey)必须足够长且保密,建议至少 16 个字符
    • 生产环境中应使用 HTTPS 传输令牌
    • 合理设置过期时间(ExpiresMinutes),避免过长
    • 可以根据需要添加更多自定义声明(如用户权限、部门等)

{"JwtSettings": {"SecretKey": "YourSuperSecretKeyWithEnoughLength123456", // 至少16个字符"Issuer": "YourCompanyName","Audience": "YourAppName","ExpiresMinutes": 30}
}

using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.IdentityModel.Tokens;
using System.Text;var builder = WebApplication.CreateBuilder(args);// 1. 读取JWT配置
var jwtSettings = new JwtSettings();
builder.Configuration.GetSection("JwtSettings").Bind(jwtSettings);
builder.Services.AddSingleton(jwtSettings);// 2. 注册JWT工具类
builder.Services.AddSingleton<JwtHelper>();// 3. 配置JWT认证服务
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme).AddJwtBearer(options =>{options.TokenValidationParameters = new TokenValidationParameters{ValidateIssuerSigningKey = true,IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtSettings.SecretKey)),ValidateIssuer = true,ValidIssuer = jwtSettings.Issuer,ValidateAudience = true,ValidAudience = jwtSettings.Audience,ValidateLifetime = true,ClockSkew = TimeSpan.Zero};});// 添加控制器支持
builder.Services.AddControllers();var app = builder.Build();// 启用认证中间件
app.UseAuthentication();
app.UseAuthorization();app.MapControllers();app.Run();

JwtSettings:

/// <summary>
/// JWT配置参数
/// </summary>
public class JwtSettings
{/// <summary>/// 密钥(必须足够长,建议至少16个字符)/// </summary>public string SecretKey { get; set; }/// <summary>/// 发行人/// </summary>public string Issuer { get; set; }/// <summary>/// 受众/// </summary>public string Audience { get; set; }/// <summary>/// 过期时间(分钟)/// </summary>public int ExpiresMinutes { get; set; }
}
using System;
using System.Collections.Generic;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;
using Microsoft.IdentityModel.Tokens;/// <summary>
/// JWT工具类
/// </summary>
public class JwtHelper
{private readonly JwtSettings _jwtSettings;public JwtHelper(JwtSettings jwtSettings){_jwtSettings = jwtSettings ?? throw new ArgumentNullException(nameof(jwtSettings));}/// <summary>/// 生成JWT令牌/// </summary>/// <param name="userId">用户ID</param>/// <param name="userName">用户名</param>/// <param name="roles">用户角色</param>/// <returns>JWT令牌</returns>public string GenerateToken(string userId, string userName, IEnumerable<string> roles = null){// 1. 创建声明(Claims)var claims = new List<Claim>{new Claim(ClaimTypes.NameIdentifier, userId), // 用户IDnew Claim(ClaimTypes.Name, userName),         // 用户名new Claim(JwtRegisteredClaimNames.Iat, new DateTimeOffset(DateTime.Now).ToUnixTimeSeconds().ToString(), ClaimValueTypes.Integer64) // 签发时间};// 添加角色声明if (roles != null){foreach (var role in roles){claims.Add(new Claim(ClaimTypes.Role, role));}}// 2. 生成密钥var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_jwtSettings.SecretKey));var credentials = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);// 3. 设置令牌过期时间var expires = DateTime.Now.AddMinutes(_jwtSettings.ExpiresMinutes);// 4. 生成令牌var token = new JwtSecurityToken(issuer: _jwtSettings.Issuer,audience: _jwtSettings.Audience,claims: claims,expires: expires,signingCredentials: credentials);// 5. 转换为字符串return new JwtSecurityTokenHandler().WriteToken(token);}/// <summary>/// 验证JWT令牌并返回声明/// </summary>/// <param name="token">JWT令牌</param>/// <returns>声明集合</returns>public ClaimsPrincipal ValidateToken(string token){var tokenHandler = new JwtSecurityTokenHandler();var key = Encoding.UTF8.GetBytes(_jwtSettings.SecretKey);try{var principal = tokenHandler.ValidateToken(token, new TokenValidationParameters{ValidateIssuerSigningKey = true,IssuerSigningKey = new SymmetricSecurityKey(key),ValidateIssuer = true,ValidIssuer = _jwtSettings.Issuer,ValidateAudience = true,ValidAudience = _jwtSettings.Audience,ValidateLifetime = true, // 验证过期时间ClockSkew = TimeSpan.Zero // 不允许有时间偏差}, out var validatedToken);return principal;}catch (Exception ex){// 令牌验证失败(过期、篡改等)throw new SecurityTokenException("无效的JWT令牌", ex);}}
}

using Microsoft.AspNetCore.Mvc;
using System.Collections.Generic;[ApiController]
[Route("api/[controller]")]
public class AuthController : ControllerBase
{private readonly JwtHelper _jwtHelper;public AuthController(JwtHelper jwtHelper){_jwtHelper = jwtHelper;}/// <summary>/// 用户登录并获取JWT令牌/// </summary>[HttpPost("login")]public IActionResult Login([FromBody] LoginRequest request){// 实际应用中需要验证用户名密码(此处简化)if (request.Username == "admin" && request.Password == "123456"){// 生成JWT令牌(包含用户ID、用户名和角色)var token = _jwtHelper.GenerateToken(userId: "1001",userName: "admin",roles: new List<string> { "Admin", "User" });return Ok(new { Token = token, ExpiresIn = 30 * 60 }); // 有效期(秒)}return Unauthorized("用户名或密码错误");}/// <summary>/// 需要JWT认证的测试接口/// </summary>[HttpGet("protected")][Authorize(Roles = "Admin")] // 仅允许Admin角色访问public IActionResult Protected(){// 从令牌中获取用户信息var userId = User.FindFirst(ClaimTypes.NameIdentifier)?.Value;var userName = User.FindFirst(ClaimTypes.Name)?.Value;return Ok(new { Message = "这是受保护的资源", UserId = userId, UserName = userName });}
}/// <summary>
/// 登录请求模型
/// </summary>
public class LoginRequest
{public string Username { get; set; }public string Password { get; set; }
}
using System.Security.Claims;
using System.Collections.Generic;namespace UserInfoProvider.Abstractions
{/// <summary>/// 用户信息提供者接口/// </summary>public interface IUserInfoProvider{/// <summary>/// 是否已认证/// </summary>bool IsAuthenticated { get; }/// <summary>/// 获取用户ID/// </summary>string UserId { get; }/// <summary>/// 获取用户名/// </summary>string UserName { get; }/// <summary>/// 获取用户角色/// </summary>IEnumerable<string> Roles { get; }/// <summary>/// 获取指定声明的值/// </summary>/// <param name="claimType">声明类型</param>/// <returns>声明值</returns>string GetClaimValue(string claimType);/// <summary>/// 获取所有声明/// </summary>/// <returns>声明集合</returns>IEnumerable<Claim> GetAllClaims();}
}
using Microsoft.AspNetCore.Http;
using System.Security.Claims;
using System.Collections.Generic;
using System.Linq;
using UserInfoProvider.Abstractions;namespace UserInfoProvider.Implementations
{/// <summary>/// 基于HttpContext的用户信息提供者/// </summary>public class HttpContextUserInfoProvider : IUserInfoProvider{private readonly IHttpContextAccessor _httpContextAccessor;private ClaimsPrincipal _user => _httpContextAccessor.HttpContext?.User;/// <summary>/// 构造函数/// </summary>public HttpContextUserInfoProvider(IHttpContextAccessor httpContextAccessor){_httpContextAccessor = httpContextAccessor ?? throw new ArgumentNullException(nameof(httpContextAccessor));}/// <summary>/// 是否已认证/// </summary>public bool IsAuthenticated => _user?.Identity?.IsAuthenticated ?? false;/// <summary>/// 用户ID/// </summary>public string UserId => GetClaimValue(ClaimTypes.NameIdentifier);/// <summary>/// 用户名/// </summary>public string UserName => GetClaimValue(ClaimTypes.Name);/// <summary>/// 用户角色/// </summary>public IEnumerable<string> Roles => GetAllClaims().Where(c => c.Type == ClaimTypes.Role).Select(c => c.Value);/// <summary>/// 获取指定声明的值/// </summary>public string GetClaimValue(string claimType){if (string.IsNullOrEmpty(claimType))throw new ArgumentException("声明类型不能为空", nameof(claimType));return !IsAuthenticated ? null : _user.FindFirstValue(claimType);}/// <summary>/// 获取所有声明/// </summary>public IEnumerable<Claim> GetAllClaims(){return !IsAuthenticated ? Enumerable.Empty<Claim>() : _user.Claims;}}
}


文章转载自:

http://0ofcDvS1.Lkthj.cn
http://YsmR8QQh.Lkthj.cn
http://mcyIv6NY.Lkthj.cn
http://schtO9ok.Lkthj.cn
http://sVvpsEOc.Lkthj.cn
http://qn6mQTPm.Lkthj.cn
http://PhVrLico.Lkthj.cn
http://eEeTqKdY.Lkthj.cn
http://wYrc0wBI.Lkthj.cn
http://miSjiI6F.Lkthj.cn
http://SvNjAJUs.Lkthj.cn
http://ev1vJO3n.Lkthj.cn
http://8m2TBFFd.Lkthj.cn
http://nvi4FjmD.Lkthj.cn
http://32aJa9zY.Lkthj.cn
http://SnPYahIY.Lkthj.cn
http://CbTIIJUo.Lkthj.cn
http://7MFHLJoW.Lkthj.cn
http://ougQXdwJ.Lkthj.cn
http://cRewmll3.Lkthj.cn
http://vODShFxd.Lkthj.cn
http://oOIP3mWD.Lkthj.cn
http://d4eEXEYX.Lkthj.cn
http://4Gcuk2pJ.Lkthj.cn
http://wRHv385k.Lkthj.cn
http://ZEg8NZ8l.Lkthj.cn
http://ml3e3be5.Lkthj.cn
http://rAehzZiX.Lkthj.cn
http://AmQnxxP8.Lkthj.cn
http://bAq49NSM.Lkthj.cn
http://www.dtcms.com/a/386538.html

相关文章:

  • webRTc 为何深受直播实现的青睐?
  • iOS App 卡顿与性能瓶颈排查实战 如何定位CPU内存GPU帧率问题、优化耗电与网络延迟(uni-app开发性能优化全流程指南)
  • Tomcat的基本配置
  • Delphi6中实现PDF文件打印功能
  • 工作笔记-----基于FreeRTOS的lwIP网络任接收过程,从MAC至协议栈
  • ZipVoice小米语音合成-MacOS可运行
  • 技术驱动学术论文写作创新:以智能工具高效生成论文提纲为例
  • (笔记)进程间通讯
  • 电力行业数字化——解读麦肯锡企业数据架构数据治理架构设计规划【附全文阅读】
  • 如何搭建redis集群(docker方式非哨兵)
  • AWS Free Tier 2.0深度技术解析与实战指南
  • 深度学习-PyTorch基本使用
  • 飞书智能查询机器人搭建说明文档
  • 速通ACM省铜第六天 赋源码(MEX Count)
  • Python自动化测试·Selenium简单介绍
  • 腾讯云轻量服务器CentOSdocker报错信息
  • 玩转Docker小游戏项目系列: Docker部署红心纸牌网页小游戏
  • Spring Cloud 注册中心:Eureka 与 Nacos 深度对比
  • 机器视觉检测中光源的作用以及分类
  • php7.4使用systemd服务器管理文件无法启动的解决办法
  • 机器视觉检测中工业相机的作用以及分类
  • MySQL 备份与还原
  • 5 分钟 SAE 极速部署 Dify,高效开发 AI 智能体应用
  • [硬件电路-233]:增强型MOS中的增强,是指通过增加正电压使得沟道从无到有的增强。耗尽型MOS中的耗尽,通过增加负电压使得沟通从最大逐渐减弱直到耗尽。
  • 整体设计 之 绪 思维导图引擎 之 引 认知系统 之 引 认知系统 之 序 认知元架构 之 概要设计收官 之1 汇总 形式化表示
  • TDengine 时序函数 DIFF 用户手册
  • 60.[前端开发-Vue3]Day02-模板语法-列表渲染-OptionsAPI-侦听器
  • UML_类图
  • 八串口服务器-工业物联网解决方案
  • 烟花爆竹储存防火防爆知识,《烟花爆竹储存作业证》考试重点