.Net Core webapi 实现JWT认证

ops/2025/1/21 17:13:22/

文章目录

    • 需求
    • 准备
    • 创建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.ppmy.cn/ops/151955.html

相关文章

Kotlin Bytedeco OpenCV 图像图像57 图像ROI

Kotlin Bytedeco OpenCV 图像图像57 图像ROI 1 添加依赖2 测试代码3 测试结果 1 添加依赖 <?xml version"1.0" encoding"UTF-8"?> <project xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xmlns"http://maven.apache.o…

使用 HTML 开发 Portal 页全解析

前言 在当今数字化时代&#xff0c;网站作为企业和个人展示信息、提供服务的重要窗口&#xff0c;其重要性不言而喻。而 Portal 页&#xff0c;作为网站的核心页面之一&#xff0c;承担着引导用户、整合信息等关键任务。那么&#xff0c;如何使用 HTML 开发一个功能齐全、界面…

【HarmonyOS NAPI 深度探索11】搭建 NAPI 开发环境:HarmonyOS DevEco Studio 全指南

【HarmonyOS NAPI 深度探索11】搭建 NAPI 开发环境&#xff1a;HarmonyOS DevEco Studio 全指南 在开始 NAPI 开发之前&#xff0c;一个高效、完善的开发环境是成功的第一步。对于 HarmonyOS 开发者来说&#xff0c;DevEco Studio 是最推荐的开发工具&#xff0c;它为 Harmony…

【开源免费】基于SpringBoot+Vue.JS夕阳红公寓管理系统(JAVA毕业设计)

本文项目编号 T 146 &#xff0c;文末自助获取源码 \color{red}{T146&#xff0c;文末自助获取源码} T146&#xff0c;文末自助获取源码 目录 一、系统介绍二、数据库设计三、配套教程3.1 启动教程3.2 讲解视频3.3 二次开发教程 四、功能截图五、文案资料5.1 选题背景5.2 国内…

基于Python机器学习的双色球数据分析与预测

python统计分析2003-2024年所有的中奖记录,通过人工智能机器学习预测双色球,个人意见,仅供参考. 声明&#xff1a;双色球具有随机性&#xff0c;任何工具无法预测。本文章仅作为技术交流&#xff0c;提供学习参考。本文所涉及的代码均为python之机器学习的代码。双色球为公益事…

C++学习第五天

创作过程中难免有不足&#xff0c;若您发现本文内容有误&#xff0c;恳请不吝赐教。 提示&#xff1a;以下是本篇文章正文内容&#xff0c;下面案例可供参考 一、构造函数 问题1 关于编译器生成的默认成员函数&#xff0c;很多童鞋会有疑惑&#xff1a;不实现构造函数的情况下…

HTML之拜年/跨年APP(改进版)

目录&#xff1a; 一&#xff1a;目录 二&#xff1a;效果 三&#xff1a;页面分析/开发逻辑 1.页面详细分析&#xff1a; 2.开发逻辑&#xff1a; 四&#xff1a;完整代码&#xff08;不多废话&#xff09; index.html部分 app.json部分 二&#xff1a;效果 三&#xff1a;页面…

《AI赋能光追:开启图形渲染新时代》

光线追踪技术是图形渲染领域的重大突破&#xff0c;能够通过模拟光的传播路径&#xff0c;精准渲染反射、折射、阴影和间接光照等效果&#xff0c;实现高度逼真的场景呈现。而人工智能的加入&#xff0c;更是为光线追踪技术带来了前所未有的变革&#xff0c;主要体现在以下几个…