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

ASP.NET Core 中的 JWT 鉴权实现

在当今的软件开发中,安全性和用户认证是至关重要的方面。JSON Web Token(JWT)作为一种流行的身份验证机制,因其简洁性和无状态特性而被广泛应用于各种应用中,尤其是在 ASP.NET Core 项目里。本文将详细介绍如何在 ASP.NET Core 应用中实现 JWT 鉴权,确保应用能够安全地验证用户身份并授权访问特定资源。

一、安装必要的 NuGet 包

dotnet add package Microsoft.AspNetCore.Authentication.JwtBearer

这个包提供了 JWT 身份验证所需的所有功能,包括对 JWT 令牌的解析和验证。

二、配置 JWT 身份验证

在应用的配置文件 appsettings.json 中添加 JWT 相关的配置信息。这些配置包括密钥、发行者、受众和令牌的有效期等:

{"JwtSettings": {"Secret": "YourSecretKeyYourSecretKeyYourSecretKeyYourSecretKey",     // 用于加密的密钥(应非常复杂)"Issuer": "YourAppName",       // 发行者"Audience": "YourAppUsers",    // 受众"ExpireMinutes": 120           // 令牌有效期}
}

在 Program.cs 文件中,需要配置 JWT 认证方案,以便 ASP.NET Core 知道如何处理 JWT 令牌:

var builder = WebApplication.CreateBuilder(args);var jwtSettings = builder.Configuration.GetSection("JwtSettings");builder.Services.AddAuthentication(options =>
{options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(options =>
{options.TokenValidationParameters = new TokenValidationParameters{ValidateIssuer = true,ValidateAudience = true,ValidateLifetime = true,ValidateIssuerSigningKey = true,ValidIssuer = jwtSettings["Issuer"],ValidAudience = jwtSettings["Audience"],IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtSettings["Secret"])),ClockSkew = TimeSpan.Zero  // 默认的 5 分钟偏移时间};options.Events = new JwtBearerEvents
{ OnMessageReceived = context =>{var token = context.Request.Headers["Authorization"].ToString()?.Replace("Bearer ", "");if (!string.IsNullOrEmpty(token)){context.Token = token;}return Task.CompletedTask;},OnAuthenticationFailed = context =>{// 如果过期,把过期信息添加到头部if (context.Exception.GetType() == typeof(SecurityTokenExpiredException)){context.Response.Headers.Append("Token-Expired", "true");}return Task.CompletedTask;} 
};
});var app = builder.Build();
app.UseAuthentication();
app.UseAuthorization();

配置了 JWT 身份验证的中间件,确保所有传入的请求都会被检查是否包含有效的 JWT 令牌。

JwtBearerEvents的订阅事件

    //  1. **OnMessageReceived**://   -触发时机:当接收到一个身份验证请求。//   -用途:用来处理接收到的原始身份验证消息,可以根据请求的具体情况来修改或取消身份验证过程。//2. * *OnTokenValidated * *://   -触发时机:在JWT被成功验证后触发。//   -用途:用来处理已验证的token,例如,可以在这里添加额外的日志记录或执行一些安全检查。//3. * *OnAuthenticationFailed * *://   -触发时机:当身份验证失败时触发。//   -用途:用来处理身份验证失败的情况,例如,记录失败原因、执行额外的错误处理逻辑等。//4. * *OnChallenge * *://   -触发时机:当需要向客户端发出一个挑战(例如,要求客户端提供凭据)时触发。//   -用途:自定义挑战的响应,例如,修改返回给客户端的`401 Unauthorized`响应。//5. * *OnForbidden * *://   -触发时机:当授权失败时触发(即用户已通过身份验证,但没有足够的权限访问特定资源)。//   -用途:自定义处理禁止访问的情况,例如,返回一个自定义的错误消息或执行其他逻辑。

三、生成 JWT Token

为了使用户能够登录并获取 JWT 令牌,需要创建一个控制器或服务来处理登录请求并生成 JWT 令牌。以下是一个简单的登录 API 示例:

using Microsoft.AspNetCore.Mvc;
using Microsoft.IdentityModel.Tokens;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;[ApiController]
[Route("api/[controller]")]
publicclassAuthController : ControllerBase
{privatereadonly IConfiguration _configuration;public AuthController(IConfiguration configuration){_configuration = configuration;}[HttpPost("login")]public IActionResult Login([FromBody] LoginRequest loginRequest){// 假设已经验证了用户名和密码if (loginRequest.Username == "admin" && loginRequest.Password == "password"){var token = GenerateJwtToken(loginRequest.Username);return Ok(new { token });}return Unauthorized();}private string GenerateJwtToken(string username){var jwtSettings = _configuration.GetSection("JwtSettings");var claims = new[]{new Claim(JwtRegisteredClaimNames.Sub, username),new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString())//添加更多的标识};var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtSettings["Secret"]));var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);var token = new JwtSecurityToken(issuer: jwtSettings["Issuer"],audience: jwtSettings["Audience"],claims: claims,expires: DateTime.Now.AddMinutes(double.Parse(jwtSettings["ExpireMinutes"])),signingCredentials: creds);returnnew JwtSecurityTokenHandler().WriteToken(token);}
}publicclassLoginRequest
{publicstring Username { get; set; }publicstring Password { get; set; }
}

四、保护 API 路由

一旦有了 JWT 令牌生成机制,接下来需要保护 API 路由,确保只有携带有效 JWT 令牌的请求可以访问受保护的资源。

可以通过在控制器或操作方法上使用 [Authorize] 特性来实现:

[AllowAnonymous]可跳过授权

[ApiController]
[Route("[controller]")]
[Authorize]
publicclassWeatherForecastController : ControllerBase
{[Authorize][HttpGet(Name = "GetWeatherForecast")]public IEnumerable<WeatherForecast> Get(){return Enumerable.Range(1, 5).Select(index => new WeatherForecast{Date = DateOnly.FromDateTime(DateTime.Now.AddDays(index)),TemperatureC = Random.Shared.Next(-20, 55),Summary = Summaries[Random.Shared.Next(Summaries.Length)]}).ToArray();}
}

五、客户端请求

客户端在请求受保护的 API 时,必须在请求头中添加 Authorization 字段,格式为 Bearer <token>

GET /api/protected/data HTTP/1.1
Host: yourdomain.com
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...

这样,服务器就能通过 JWT 中间件验证令牌的有效性,并允许或拒绝请求。

六、扩展:Swagger集成,传递验证

需要使用包Swashbuckle.AspNetCore

builder.Services.AddSwaggerGen(options => options.SwaggerTokenConfigure());
if (app.Environment.IsDevelopment())
{app.UseSwagger();app.UseSwaggerUI();
}

SwaggerConfiguration将token保存到swagger并传递到后台

public staticclassSwaggerConfiguration
{public static void SwaggerTokenConfigure(this SwaggerGenOptions options){options.SwaggerDoc("v1", new OpenApiInfo{Title = "JWT Auth API",Version = "v1",Description = "A sample API for JWT Authentication"});options.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme{Description = "JWT Authorization header using the Bearer scheme.",Name = "Authorization",In = ParameterLocation.Header,Type = SecuritySchemeType.Http,Scheme = "Bearer",BearerFormat = "JWT"});options.AddSecurityRequirement(new OpenApiSecurityRequirement{{new OpenApiSecurityScheme{Reference = new OpenApiReference{Type = ReferenceType.SecurityScheme,Id = "Bearer"}},Array.Empty<string>()}});}
}

有关swagger更多的详细配置,请参考
https://mp.weixin.qq.com/s/Xke2EyUHuxR_RdHbSXP5Ew

分组:https://mp.weixin.qq.com/s/Ut9leANrq4pJMgOQFmVkqg

七、扩展:获取身份验证信息

老规矩,先注册

builder.Services.AddHttpContextAccessor();
builder.Services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
builder.Services.AddTransient<IAppUser, AppUser>();

存放用户信息的接口和实现类

    public interfaceIAppUser{string Username { get; }string HeaderToken { get; }}publicclassAppUser : IAppUser{privatereadonly HttpContext _httpContext;public AppUser(IHttpContextAccessor httpContextAccessor){_httpContext = httpContextAccessor?.HttpContext;}publicstring Username { get => _httpContext?.User.Claims.FirstOrDefault(s => s.Type == "Username")?.Value.ToString()??""; }publicstring HeaderToken{get{if (_httpContext.Request.Headers.ContainsKey("Authorization")){return _httpContext?.Request.Headers["Authorization"].ToString().Replace("Bearer ", "").Trim();}returnstring.Empty;}}}

直接使用

 private readonly IAppUser _appUser ;public AuthController(IConfiguration configuration, IAppUser appUser){_configuration = configuration;_appUser=appUser;}[HttpGet]public IActionResult Getuserinfo(){return Ok(new { _appUser.Username, _appUser.HeaderToken });}

可以成功获取到用户存放的token信息,不过现在还有一个弊端,就是每次都需要构造注入才可以过去用户信息,是比较麻烦的,其实我们可以通过封装一下,将AppUser存放到App全局配置里面直接静态获取,这样在需要获取用户信息的时候,就不需要每次都构造注入了
等后面有机会出优化和封装教程,或者直接参考:https://gitee.com/Pridejoy/MalusAdmin

八、可选:角色授权

如果应用需要基于角色进行授权,可以在生成 JWT 令牌时添加角色信息:

private string GenerateJwtToken(string username)
{var claims = new[]{new Claim(JwtRegisteredClaimNames.Sub, username),new Claim(ClaimTypes.Role, "Admin"),  // 添加角色new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString())};// 剩余代码与前面一致
}

然后,可以使用 [Authorize(Roles = "Admin")] 特性来限定只有特定角色的用户才能访问:

[Authorize(Roles = "Admin")]
[HttpGet("admin-data")]
public IActionResult GetAdminData()
{return Ok(new { message = "This is admin data" });
}

总结

通过以上操作,就可以在 ASP.NET Core 应用中实现 JWT 鉴权,确保你的应用能够安全地验证用户身份并授权访问特定资源。JWT 的无状态特性和灵活性使其成为现代 Web 应用中身份验证的理想选择。

相关文章:

ASP.NET Core 中的 JWT 鉴权实现

在当今的软件开发中&#xff0c;安全性和用户认证是至关重要的方面。JSON Web Token&#xff08;JWT&#xff09;作为一种流行的身份验证机制&#xff0c;因其简洁性和无状态特性而被广泛应用于各种应用中&#xff0c;尤其是在 ASP.NET Core 项目里。本文将详细介绍如何在 ASP.…...

PyTorch基本功能与实现代码

PyTorch是一个开源的深度学习框架&#xff0c;提供了丰富的函数和工具&#xff0c;以下为其主要功能的归纳&#xff1a; 核心数据结构&#xff1a; • 张量&#xff08;Tensor&#xff09;&#xff1a;类似于Numpy的ndarray&#xff0c;是PyTorch中基本的数据结构&#xff0c…...

SparkSQL数据模型综合实践

文章目录 1. 实战概述2. 实战步骤2.1 创建数据集2.2 创建数据模型对象2.2.1 创建常量2.2.2 创建加载数据方法2.2.3 创建过滤年龄方法2.2.4 创建平均薪水方法2.2.5 创建主方法2.2.6 查看完整代码 2.3 运行程序&#xff0c;查看结果 3. 实战小结 1. 实战概述 在本次实战中&#…...

3 查找重复的电子邮箱(having与where区别,distinct去重使用)

3 查找重复的电子邮箱&#xff08;having与where区别&#xff0c;distinct去重使用&#xff09; 表: Person ---------------------- | Column Name | Type | ---------------------- | id | int | | email | varchar | ---------------------- id 是该…...

uniapp——App 监听下载文件状态,打开文件(三)

5 实现下载文件并打开 这里演示&#xff0c;导出Excel 表格 文章目录 5 实现下载文件并打开DEMO监听下载进度效果图为什么 totalSize 一直为0&#xff1f; 相关Api&#xff1a; downloader DEMO 提示&#xff1a; 请求方式支持&#xff1a;GET、POST&#xff1b;POST 方式需要…...

循环队列(C语言)

从今天开始我会开启一个专栏leetcode每日一题&#xff0c;大家互相交流代码经验&#xff0c;也当作我每天练习的自我回顾。第一天的内容是leetcode622.设计循环队列。 一、题目详细 设计你的循环队列实现。 循环队列是一种线性数据结构&#xff0c;其操作表现基于 FIFO&#…...

数据可视化:让数据讲故事的艺术

目录 1 前言2 数据可视化的基本概念2.1 可视化的核心目标2.2 传统可视化手段 3 数据可视化在知识图谱中的应用3.1 知识图谱的可视化需求3.2 知识图谱的可视化方法 4 数据可视化叙事&#xff1a;让数据讲故事4.1 叙事可视化的关键要素4.2 数据可视化叙事的实现方法 5 数据可视化…...

雷电9最新版安装Magisk+LSPosd(新手速通)

大家好啊&#xff01;我是NiJiMingCheng 我的博客&#xff1a;NiJiMingCheng 在安卓系统的定制与拓展过程中&#xff0c;获取 ROOT 权限以及安装各类框架是进阶玩家常用的操作&#xff0c;这可以帮助我们实现更多系统层面的个性化功能。今天&#xff0c;我将为大家详细介绍如何…...

Ubuntu 24.04 LTS 开启 SMB 服务,并通过 windows 访问

Ubuntu 24.04 LTS 背景资料 Ubuntu服务器折腾集Ubuntu linux 文件权限Ubuntu 空闲硬盘挂载到 文件管理器的 other locations Ubuntu开启samba和window共享文件 Ubuntu 配置 SMB 服务 安装 Samba 确保 Samba 已安装。如果未安装&#xff0c;运行以下命令进行安装&#xff…...

使用Websocket进行前后端实时通信

1、引入jar&#xff0c;spring-websocket-starter <dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-websocket</artifactId> </dependency> 2、配置websocket config import org.springframe…...

vue2使用flv.js在浏览器打开flv格式视频

组件地址&#xff1a;GitHub - bilibili/flv.js: HTML5 FLV Player flv.js 仅支持 H.264 和 AAC/MP3 编码的 FLV 文件。如果视频文件使用了其他编码格式就打不开。 flv.vue <template><div><el-dialog :visible.sync"innerVisibleFlv" :close-on-pre…...

OpenCV相机标定与3D重建(61)处理未校准的立体图像对函数stereoRectifyUncalibrated()的使用

操作系统&#xff1a;ubuntu22.04 OpenCV版本&#xff1a;OpenCV4.9 IDE:Visual Studio Code 编程语言&#xff1a;C11 算法描述 为未校准的立体相机计算一个校正变换。 cv::stereoRectifyUncalibrated 是 OpenCV 库中的一个函数&#xff0c;用于处理未校准的立体图像对。该函…...

[cg] glProgramBinary

参考&#xff1a; glProgramBinary - OpenGL 4 Reference Pages opengl 通过gpu编译好的 shader 可以存储到二进制文件中&#xff0c;第二次使用的时候直接加载二进制文件即可&#xff0c; glProgramBinary用于加载shader的二进制数据 实列代码如下&#xff1a; // 假设已经…...

LeetCode hot 力扣热题100 二叉树的最大深度

class Solution { public:int maxDepth(TreeNode* root) {if (root nullptr) {return 0;}int l_depth maxDepth(root->left);int r_depth maxDepth(root->right);return max(l_depth, r_depth) 1;} }; 代码作用 该函数通过递归计算二叉树的最大深度&#xff08;从根节…...

速通Docker === 网络

目录 Docker网络详解 容器之间直接通信的弊端 &#xff08;一&#xff09;启动容器 &#xff08;二&#xff09;进入容器并发起请求 &#xff08;三&#xff09;请求流程 &#xff08;四&#xff09; 弊端分析 一、Docker网络基础 &#xff08;一&#xff09;容器IP分配…...

【MySQL — 数据库基础】深入解析MySQL常用数据类型

常用数据类型 创建完数据库之后&#xff0c;就要在数据库中创建表&#xff0c;表中存储的数据记录&#xff0c;一条记录由不同的列组成&#xff0c;每条列都需要自己的类型&#xff1b;并且表中的多个行对应的列的数据类型&#xff0c;都必须是相同的&#xff1b; 那么每个…...

Linux高级--3.3.1 C++ spdlog 开源异步日志方案

一、基本介绍 spdlog 是由 Gustav S. 在 2015 年开发的一个高性能 C 日志库。开发这个库的主要目的是为了提供一个非常快速、轻量、易于使用的日志工具&#xff0c;特别适合需要高性能、低延迟日志记录的 C 应用程序。&#xff08;由于源码现在比较难下载&#xff0c;我把压缩…...

电梯系统的UML文档05

Dispatcher 不控制实际的电梯组件&#xff0c;但它在软件系统中是重要的。每一个电梯有一个ispatcher&#xff0c;主要功能是计算电梯的移动方向、移动目的地以及保持门的打开时间。它和系统中除灯控制器以外的几乎所有控制对象交互。 安全装置也是一个环境对象&#xff0c;它…...

如何使 LLaMA-Factory 支持 google/gemma-2-2b-jpn-it 的微调

如何使 LLaMA-Factory 支持 google/gemma-2-2b-jpn-it 的微调 追加&#xff0c; "Gemma-2-2B-JPN-Instruct": {DownloadSource.DEFAULT: "google/gemma-2-2b-jpn-it",},修改 constants.py&#xff0c; vi ./src/llamafactory/extras/constants.py---"…...

MySQL中日期和时间戳的转换:字符到DATE和TIMESTAMP的相互转换

在MySQL中&#xff0c;经常需要在 DATE、TIMESTAMP 和字符串之间进行相互转换。以下是一些常见的转换方法&#xff1a; 1. 字符串到日期/时间类型 字符串转 DATE: 使用 STR_TO_DATE() 函数将字符串转换为 DATE 类型。你需要提供字符串的格式。 SELECT STR_TO_DATE(2024-08-24,…...

C++中显示与隐式加载dll的使用与区别

一、什么是 DLL&#xff1f;DLL&#xff08;Dynamic Link Library&#xff09; 是 Windows 下的动态链接库&#xff0c;包含可被多个程序共享的函数、资源或类。使用 DLL 可以实现代码复用、模块化设计和插件机制。在 C 中&#xff0c;调用 DLL 中的函数有两种主要方式&#xf…...

信息系统项目管理师核心知识点精讲

一、项目整合管理(重点:项目章程与项目管理计划) 知识点详解: 项目整体管理是项目管理知识体系的核心,它确保项目各要素协调统一。在考试中,特别要掌握项目章程和项目管理计划的区别与联系。 项目章程是项目的“出生证明”,由项目发起人发布。它正式授权项目,赋予项…...

苏州创新药20年,站上全球产业洗牌暴风眼

一个城市的创新药产业集群如何从无到有&#xff0c;又如何在全球化临界点寻找自己的位置。文&#xff5c;徐鑫编&#xff5c;任晓渔过去一年多&#xff0c;苏州是全球创新药产业版图中一个绕不过去的城市。大额海外授权交易频繁传出&#xff0c;在中国高端制造走出去的背景下&a…...

一次搞懂内存取证:用Volatility3和Cobalt Strike分析工具复现VNCTF‘来一把紧张刺激的CS’

实战内存取证&#xff1a;从Volatility3到Cobalt Strike信标分析全解析 在网络安全事件响应中&#xff0c;内存取证往往是发现高级威胁的最后一道防线。当攻击者使用文件无落地的技术时&#xff0c;传统的磁盘取证可能一无所获&#xff0c;而内存中却保留着攻击行为的完整痕迹。…...

别再用SonarQube凑数了!DeepSeek原生圈复杂度引擎的6大颠覆性能力(含GitHub私有部署密钥)

更多请点击&#xff1a; https://kaifayun.com 第一章&#xff1a;DeepSeek圈复杂度分析的底层原理与范式革命 DeepSeek圈复杂度分析并非传统McCabe度量的简单复刻&#xff0c;而是基于控制流图&#xff08;CFG&#xff09;动态重构与语义感知路径裁剪的双重机制构建的新范式。…...

终极免费方案:WandEnhancer完整解锁WeMod Pro功能快速指南

终极免费方案&#xff1a;WandEnhancer完整解锁WeMod Pro功能快速指南 【免费下载链接】Wand-Enhancer Advanced UX and interoperability extension for Wand (WeMod) app 项目地址: https://gitcode.com/gh_mirrors/we/Wand-Enhancer 你是否渴望享受WeMod Pro会员的所…...

告别数据饥荒:用PyTorch手把手实现原型网络(Prototypical Networks)做电影评论情感分类

告别数据饥荒&#xff1a;用PyTorch手把手实现原型网络做电影评论情感分类 在自然语言处理领域&#xff0c;情感分析一直是热门研究方向&#xff0c;但现实中的开发者常面临一个尴尬困境&#xff1a;标注数据太少。传统深度学习方法动辄需要成千上万的标注样本&#xff0c;而实…...

LangGraph状态机工程:构建复杂AI工作流的完整指南

传统RAG&#xff08;检索增强生成&#xff09;在处理简单的"单跳"问题时表现良好——“文章里提到了什么” “这个概念是什么意思”——但当问题涉及多个实体之间的关系、需要跨多个文档推理时&#xff0c;传统RAG就显得力不从心。GraphRAG&#xff08;Graph-based R…...

告别硬编码!在UE5.1里用蓝图动态配置MySQL连接参数(控件蓝图实战)

动态配置MySQL连接&#xff1a;UE5.1控件蓝图的工程化实践在游戏开发中&#xff0c;数据库连接往往是项目架构中不可或缺的一环。传统硬编码方式虽然简单直接&#xff0c;却带来了维护困难、安全性差、灵活性低等一系列问题。本文将深入探讨如何在UE5.1中构建一个完全动态化的M…...

Arcmap实操:如何用‘渔网’给你的地图做一次‘CT扫描’——以韶关市路网密度可视化为例

Arcmap实操&#xff1a;如何用‘渔网’给你的地图做一次‘CT扫描’——以韶关市路网密度可视化为例 想象一下&#xff0c;医生通过CT扫描将人体内部结构分层呈现&#xff0c;而GIS中的"渔网"工具同样能对城市路网进行"切片式"分析。这种空间离散化技术&…...