.Net Core webapi 实现JWT认证

文章目录

    • 需求
    • 准备
    • 创建JWT配置
    • 创建JWTService
    • 注册JWT
    • 创建中间件读取jwt的token
    • 在需要的接口上添加属性
    • 启动认证
    • 启动swagger的授权认证
    • 使用

需求

实现一个记录某个用户所有操作的功能

准备

  1. 创建你的webapi项目
  2. 从nuget下载安装JWT资源包根据你的项目使用.net版本下载对应的jwt版本,测试项目使用了.net8.0:
    Microsoft.AspNetCore.Authentication.JwtBearer
    在这里插入图片描述

创建JWT配置

在appsettings.json中新增JWTOptions

"JWTOptions": {//你的jwt加密密钥"SecretKey": "ThisIsASecretKeyForJWTTokenGeneration","Issuer": "localhost", //令牌颁发者"Audience": "localhost", //令牌接收者"Expired": 5 //令牌过期时间
}

创建jwt配置类并注册

public class JWTOptions
{/// <summary>/// jwt加密密钥,任意字符串/// </summary>public string SecretKey { get; set; }/// <summary>/// 颁发者/// </summary>public string Issuer { get; set; }/// <summary>/// 接收者/// </summary>public string Audience { get; set; }/// <summary>/// 过期时间/// </summary>public int Expired { get; set; }
}//在program.cs中注册该option
builder.Services.Configure<JWTOptions>(builder.Configuration.GetSection("JWTOptions"));

创建JWTService

创建服务生成token

public class GenerateJWTService
{private readonly JWTOptions _options;public GenerateJWTService(IOptionsMonitor<JWTOptions> options){_options = options.CurrentValue;}public JWTokenTResult GenerateToken(string userName){var claims = new List<Claim> {new("userName", userName),new(JwtRegisteredClaimNames.Sub, userName),};var validFrom = DateTime.Now;var validTo = DateTime.Now.AddMinutes(10);//创建令牌var jwt = new JwtSecurityToken(issuer: _options.Issuer,audience: _options.Audience,claims: claims,notBefore: validFrom,expires: validTo,signingCredentials: new Microsoft.IdentityModel.Tokens.SigningCredentials(new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_options.SecretKey)), SecurityAlgorithms.HmacSha256)) ;string accessToken = new JwtSecurityTokenHandler().WriteToken(jwt);return new JWTokenTResult{AccessToken = accessToken,ExpireIn = _options.Expired * 60,TokenType = JwtBearerDefaults.AuthenticationScheme};}
}//jwt模型
public class JWTokenTResult
{public string AccessToken {  get; set; }public string RefreshToken {  get; set; }/// <summary>/// 过期时间,单位s/// </summary>public int ExpireIn {  get; set; }public string TokenType {  get; set; }public LoginUserModel User { get; set; }
}public class LoginUserModel
{public string UserId { get; set; }public string UserName { get; set; }public string Roles {  get; set; }
}

注册JWT

把jwt注册到服务中

public static void AddJWTTokenAuth(this IServiceCollection serivces, IConfiguration configuration)
{var jwtSettings = configuration.GetSection("JWTOptions");serivces.Configure<JWTOptions>(configuration.GetSection("JWTOptions"));serivces.AddAuthentication(JwtBearerDefaults.AuthenticationScheme).AddJwtBearer(options =>{options.SaveToken = true;options.TokenValidationParameters = new TokenValidationParameters{ValidateIssuer = true,ValidateAudience = true,ValidateLifetime = true,//启动token有效时间校验ClockSkew = TimeSpan.Zero, //默认ClockSkew是5分钟,当前时间和JWT的过期时间之间的差距小于 5 分钟,Token 仍然会被认为是有效的ValidateIssuerSigningKey = true,ValidIssuer = jwtSettings["Issuer"],ValidAudience = jwtSettings["Audience"],IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtSettings["SecretKey"]))};});
}//在program.cs中调用
builder.Services.AddJWTTokenAuth(builder.Configuration);

创建中间件读取jwt的token

using System.IdentityModel.Tokens.Jwt;
using System.Text;namespace JWTTest
{public class UserMiddleware{private readonly RequestDelegate _next;private readonly GenerateJWTService _generateJWTService;public UserMiddleware(RequestDelegate next, GenerateJWTService generateJWTService){_next = next;_generateJWTService = generateJWTService;}public async Task InvokeAsync(HttpContext context){if(context.User.Identity.IsAuthenticated){var requestUrl = $"{context.Request.Scheme}://{context.Request.Host}{context.Request.Path}{context.Request.QueryString}";if(context.Request.Method.ToUpper() == "GET"){}else{context.Request.EnableBuffering();// 启用请求体流缓冲,以便多次读取var reader = new StreamReader(context.Request.Body, Encoding.UTF8);var body = await reader.ReadToEndAsync();// 将请求体位置重置,避免后续中间件或控制器读取不到context.Request.Body.Position = 0;}var userName = context.User.Claims.FirstOrDefault(c => c.Type == "userName")?.Value;Console.WriteLine($"{userName} request");var token = context.Request.Headers["Authorization"].FirstOrDefault()?.Split(" ").Last();var tokenhandler = new JwtSecurityTokenHandler();var jwtToken = tokenhandler.ReadToken(token) as JwtSecurityToken;if(jwtToken != null){//如果token将要过期,实现用户无感刷新,只需要前端判断response的header中是否有New-Access-Token,有就替换原来的tokenif(jwtToken.ValidTo - DateTime.UtcNow < TimeSpan.FromMinutes(5)){var newAccessToken = _generateJWTService.GenerateToken(userName);context.Response.Headers["New-Access-Token"] = "";//newAccessToken;}}}await _next(context);}}
}

在需要的接口上添加属性

在需要的接口上添加[Authorize]属性,也可以加到controller上,然后给不需要认证的接口添加[AllowAnonymous],跳过认证

using JWTTest.Model;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;namespace JWTTest.Controllers
{[ApiController][Route("[controller]/[action]")]public class WeatherForecastController : ControllerBase{private static readonly string[] Summaries = new[]{"Freezing", "Bracing", "Chilly", "Cool", "Mild", "Warm", "Balmy", "Hot", "Sweltering", "Scorching"};private readonly ILogger<WeatherForecastController> _logger;private readonly GenerateJWTService _generateJWTService;public WeatherForecastController(ILogger<WeatherForecastController> logger, GenerateJWTService generateJWTService){_logger = logger;_generateJWTService = generateJWTService;}[HttpGet(Name = "GetWeatherForecast")][Authorize]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();}[Authorize][HttpPost("test/testpost")]public ActionResult Test(LoginUserModel loginUserModel){return default;}[HttpGet("/login")]public ActionResult GetLogin(string name, string password){var jwtTokenResult = _generateJWTService.GenerateToken(name);//jwtTokenResult.refresh_token = refreshToken;return Ok(jwtTokenResult);//这里可按需返回   如果不想返回用户信息  比如密码  可以在_generateJwt.GenerateEncodedTokenAsync去掉哦}}
}

启动认证

//在program.cs中启动认证,顺序不能错
app.UseAuthentication(); //身份验证,验证令牌信息
app.UseAuthorization();//授权

启动swagger的授权认证

using Microsoft.OpenApi.Models;namespace Wonder.OHTC.Backend.Extension
{public static class SwaggerAuthExtension{/// <summary>/// 为swagger添加authorization/// </summary>/// <param name="services"></param>public static void AddSwaggerExtension(this IServiceCollection services){services.AddSwaggerGen(options =>{// 为 Swagger JSON and UI设置xml文档注释路径var basePath = Path.GetDirectoryName(typeof(Program).Assembly.Location);//获取应用程序所在目录(绝对,不受工作目录影响,建议采用此方法获取路径)var xmlPath = Path.Combine(basePath, "Wonder.OHTC.Backend.xml");// 添加控制器层注释,true表示显示控制器注释 false表示只显示API接口的注释options.IncludeXmlComments(xmlPath, true);options.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme(){In = ParameterLocation.Header,//jwt默认存放Authorization信息的位置(请求头中)Description = "Please enter JWT with bearer into field",Name = "Authorization",//jwt默认的参数名称Type = SecuritySchemeType.ApiKey});options.AddSecurityRequirement(new OpenApiSecurityRequirement(){{new OpenApiSecurityScheme{Reference = new OpenApiReference{Type = ReferenceType.SecurityScheme,Id = "Bearer"}},Array.Empty<string>()}});});}}
}//在program.cs中调用
builder.Services.AddSwaggerExtension();

也可以直接在program里面直接注册jwt


using JWTTest.Model;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.IdentityModel.Tokens;
using Microsoft.OpenApi.Models;
using System.Text;namespace JWTTest
{public class Program{public static void Main(string[] args){var builder = WebApplication.CreateBuilder(args);// Add services to the container.builder.Services.AddControllers();// Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbucklebuilder.Services.AddEndpointsApiExplorer();builder.Services.AddSwaggerGen(options =>{options.AddSecurityDefinition("Bearer", new Microsoft.OpenApi.Models.OpenApiSecurityScheme(){In = Microsoft.OpenApi.Models.ParameterLocation.Header,//jwt默认存放Authorization信息的位置(请求头中)Description = "Please enter JWT with bearer into field",Name = "Authorization",//jwt默认的参数名称Type = Microsoft.OpenApi.Models.SecuritySchemeType.ApiKey});options.AddSecurityRequirement(new Microsoft.OpenApi.Models.OpenApiSecurityRequirement(){{new OpenApiSecurityScheme{Reference = new OpenApiReference{Type = ReferenceType.SecurityScheme,Id = "Bearer"}},new string[]{}}});});var jwtSettings = builder.Configuration.GetSection("JWTOptions");builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme).AddJwtBearer(options =>{options.SaveToken = true;options.TokenValidationParameters = new TokenValidationParameters{ValidateIssuer = true,ValidateAudience = true,ValidateLifetime = true,//启动token有效时间校验ClockSkew = TimeSpan.Zero, //默认ClockSkew是5分钟,当前时间和JWT的过期时间之间的差距小于 5 分钟,Token 仍然会被认为是有效的ValidateIssuerSigningKey = true,ValidIssuer = jwtSettings["Issuer"],ValidAudience = jwtSettings["Audience"],IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtSettings["SecretKey"]))};});builder.Services.Configure<JWTOptions>(builder.Configuration.GetSection("JWTOptions"));builder.Services.AddSingleton<GenerateJWTService>();var app = builder.Build();// Configure the HTTP request pipeline.if (app.Environment.IsDevelopment()){app.UseSwagger();app.UseSwaggerUI();}app.UseHttpsRedirection();app.UseAuthentication(); //身份验证app.UseAuthorization();//授权app.MapControllers();app.UseMiddleware<UserMiddleware>();app.Run();}}
}

使用

在这里插入图片描述

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

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

相关文章

leetcode203-移除链表元素

leetcode203 什么是链表 之前不懂链表的数据结构&#xff0c;一看到链表的题目就看不明白 链表是通过next指针来将每个节点连接起来的&#xff0c;题目中给的链表是单向链表&#xff0c;有两个值&#xff0c;一个val表示值&#xff0c;一个next&#xff1a;表示连接的下一个…

在21世纪的我用C语言探寻世界本质——字符函数和字符串函数(2)

人无完人&#xff0c;持之以恒&#xff0c;方能见真我&#xff01;&#xff01;&#xff01; 共同进步&#xff01;&#xff01; 文章目录 一、strncpy函数的使用二、strncat函数的使用三、strncmp函数的使用四、strstr的使用和模拟实现五、strtok函数的使用六、strerror和pe…

stack_queue的底层,模拟实现,deque和priority_queue详解

文章目录 适配器Stack的模拟实现Queue的模拟实现vector和list的对比dequedeque的框架deque的底层 priority_queuepriority_queue的使用priority_queue的底层仿函数的使用仿函数的作用priority_queue模拟实现 适配器 适配器是一种模式&#xff0c;这种模式将类的接口转化为用户希…

LLM - 大模型 ScallingLaws 的 CLM 和 MLM 中不同系数(PLM) 教程(2)

欢迎关注我的CSDN&#xff1a;https://spike.blog.csdn.net/ 本文地址&#xff1a;https://spike.blog.csdn.net/article/details/145188660 免责声明&#xff1a;本文来源于个人知识与公开资料&#xff0c;仅用于学术交流&#xff0c;欢迎讨论&#xff0c;不支持转载。 Scalin…

杰盛微 IRS2336STRPBF 700V带使能和故障报告的三相反逻辑驱动芯片 SOP28封装

IRS2336STRPBF 700V带使能和故障报告的三相反逻辑驱动芯片 IRS2336是 N型高压、高速功率 MOSFET/IGBT高低侧三相栅极驱动芯片&#xff0c;包含三路独立的半桥驱动电路。内部集成了欠压保护和过流保护功能&#xff0c;出现异常时立即关断六通道输出。提供外部使能控制可同时关断…

深入理解第三范式(3NF):数据库设计中的重要性与实践

title: 深入理解第三范式(3NF):数据库设计中的重要性与实践 date: 2025/1/17 updated: 2025/1/17 author: cmdragon excerpt: 在数据库设计中,规范化是确保数据完整性、减少冗余和提高查询效率的关键过程。第三范式(3NF)作为关系数据库设计的高级规范,建立在前两范式…

mongoose 支持https踩坑纪实

简述 mongoose是C编写的嵌入式web服务&#xff0c;它能够支持https协议&#xff0c;可以简单的部署&#xff0c;但要做到完美部署&#xff0c;不是那么容易。 部署方法 本人使用的是最新的7.16版&#xff0c;以前版本似乎是要通过修改 头文件中的 MG_ENABLE_SSL 宏定义&…

RK3576 Android14 状态栏和导航栏增加显示控制功能

问题背景&#xff1a; 因为RK3576 Android14用户需要手动控制状态栏和导航栏显示隐藏控制&#xff0c;包括对锁屏后下拉状态栏的屏蔽&#xff0c;在设置功能里增加此功能的控制&#xff0c;故参考一些博客完成此功能&#xff0c;以下是具体代码路径的修改内容。 解决方案&…

C#高级:通过 Assembly 类加载 DLL 和直接引用DLL的方法大全

一、主项目不添加引用 &#xff08;主项目不添加引用&#xff0c;而是通过路径获取指定dll&#xff09; 1.打印类的属性名称 namespace ReflectionDemo {class Program{static void Main(string[] args){// 指定【编译输出】的项目类库dll&#xff08;启动项目编译输出目录下…

【k8s面试题2025】1、练气期

主要通过呼吸吐纳等方法&#xff0c;将外界的天地灵气吸入体内&#xff0c;初步改造身体&#xff0c;使身体素质远超常人。 文章目录 docker 和虚拟机的不同Kubernetes 和 docker 的关系Kube-proxy IPVS 和 iptables 的异同蓝绿发布Kubernetes中常见的数据持久化方式关于 Docke…

音视频入门基础:RTP专题(4)——FFmpeg源码中,判断某文件是否为SDP文件的实现

一、引言 执行《音视频入门基础&#xff1a;RTP专题&#xff08;2&#xff09;——使用FFmpeg命令生成RTP流》中的“媒体文件转推RTP的FFmpeg命令”会生成一个SDP文件&#xff0c;该文件内容如下&#xff1a; v0 o- 0 0 IN IP4 127.0.0.1 sNo Name t0 0 atool:libavformat 61…

【大数据2025】Hadoop 万字讲解

文章目录 一、大数据通识大数据诞生背景与基本概念大数据技术定义与特征大数据生态架构概述数据存储数据计算与易用性框架分布式协调服务和任务调度组件数仓架构流处理架构 二、HDFSHDFS 原理总结一、系统架构二、存储机制三、数据写入流程四、心跳机制与集群管理 安全模式&…

电脑换固态硬盘

参考&#xff1a; https://baijiahao.baidu.com/s?id1724377623311611247 一、根据尺寸和缺口可以分为以下几种&#xff1a; 1、M.2 NVME协议的固态 大部分笔记本是22x42MM和22x80MM nvme固态。 在京东直接搜&#xff1a; M.2 2242 M.2 2280 2、msata接口固态 3、NGFF M.…

回顾2024年在CSDN的成长

文章目录 我与CSDN的初次邂逅初学阶段的阅读CSDN&#xff1a;编程新手的避风港初学者的福音&#xff1a;细致入微的知识讲解考试复习神器&#xff1a;技术总结的“救命指南”曾经的自己&#xff1a;为何迟迟不迈出写博客的第一步兴趣萌芽&#xff1a;从“读”到“想写”的初体验…

抖音ip属地不准是什么原因?可以改吗

在数字化时代&#xff0c;社交媒体平台如抖音已成为人们日常生活的重要组成部分。随着各大平台对用户隐私和数据安全的日益重视&#xff0c;IP属地的显示功能应运而生。然而&#xff0c;不少抖音用户在使用过程中发现&#xff0c;显示的IP属地与实际位置存在偏差&#xff0c;这…

Win11 安装与配置 Java环境 JDK(以JDK11为例)

0&#xff0c;下载JDK 访问JDK官网&#xff1a;Java Downloads | Oracle 选择对应版本进行下载&#xff0c;目前21和23都是可以直接下载的 但是如果需要下载旧版本&#xff0c;往下拉找到要下载的版本&#xff0c;不过这时候下载就需要登录账号了&#xff0c;注册一个就成 2&…

LabVIEW串口通信调试与数据接收问题

在使用LabVIEW进行串口通信时&#xff0c;常常会遇到无法接收数据的情况。这可能与串口设置、连接、设备响应等多方面因素相关。本文将详细讨论如何使用LabVIEW进行串口通信&#xff0c;并提供常见问题的排查与解决方法&#xff0c;帮助用户更高效地进行数据接收调试。通过调整…

概率扩散去噪模型DDPM

文章目录 摘要abstract高斯噪声扩散模型正向过程逆向过程 论文阅读论文创新点解决的问题 总结参考文献 摘要 本周主要学习了高斯噪声在扩散模型中的应用及相关算法实现。扩散模型受到自然现象的启发&#xff0c;通过在图像中引入高斯噪声&#xff0c;模拟出扩散效果&#xff0…

Python操作Excel——openpyxl使用笔记(3)

3 单元格基本操作 3.1 访问单元格和读写其内容 在前面的例子中&#xff0c;已经简单演示过了向单元格中写入和读取数据。这里进一步提供访问单元格的一些方法。和前面一样&#xff0c;使用工作表的索引方式&#xff0c;可以快速定位一个单元格&#xff1a; import openpyxl w…

2025.1.18机器学习笔记:PINN文献精读

第三十周周报 一、文献阅读题目信息摘要Abstract创新点物理背景网络框架实验实验一&#xff1a;直道稳定流条件实验二&#xff1a;环状网络中的非稳定流条件 结论缺点及展望 二、代码实践总结 一、文献阅读 题目信息 题目&#xff1a;《Enhanced physics-informed neural net…