在 .NET 8/9 中使用 AppUser 进行 JWT 令牌身份验证

文章目录

  • 一、引言
  • 二、什么是 JSON Web 令牌?
  • 三、什么是 JSON Web 令牌结构?
  • 四、设置 JWT 令牌身份验证
    • 4.1 创建新的 .NET 8 Web API 项目
    • 4.2 安装所需的 NuGet 软件包
    • 4.3 创建 JWT 配置模型
    • 4.4 将 JWT 配置添加到您的 appsettings.json 中
    • 4.5 为 Configuration 配置 DIProgram.cs
    • 4.6 配置 JWT 身份验证扩展
    • 4.7 在 Program.cs 配置
    • 4.8 创建 Token 生成服务
    • 4.9 注册 Token Service
    • 4.10 添加登录端点或控制器
    • 4.11 新增 SwaggerConfiguration(方便测试)
    • 4.12 添加 AppUser
    • 4.13 为所有 Controller 或端点添加 Authorize 属性
  • 五、测试


一、引言

本文介绍了在 .NET 8 Web 应用程序中通过 AppUser 类实现 JWT 令牌身份验证的过程。JWT 身份验证是保护 API 的标准方法之一,它允许无状态身份验证,因为签名令牌是在客户端和服务器之间传递的。
在这里插入图片描述

二、什么是 JSON Web 令牌?

JSON Web 令牌(JWT)是一种开放标准(RFC 7519),它定义了一种紧凑且自包含的方式,用于将信息作为 JSON 对象在各方之间安全地传输。此信息是经过数字签名的,因此可以验证和信任。可以使用密钥(使用 HMAC 算法)或使用 RSAECDSA 的公钥/私钥对对 JWT 进行签名。

三、什么是 JSON Web 令牌结构?

在其紧凑形式中,JSON Web 令牌由三个部分组成,由点(.)分隔,它们是:

  • 页眉
  • 有效载荷
  • 签名

因此,JWT 通常如下所示:xxxxx.yyyyy.zzzzz

四、设置 JWT 令牌身份验证

4.1 创建新的 .NET 8 Web API 项目

dotnet new webapi -n JwtAuthApp

4.2 安装所需的 NuGet 软件包

dotnet add package Microsoft.AspNetCore.Authentication.JwtBearer
dotnet add package Microsoft.IdentityModel.Tokens

4.3 创建 JWT 配置模型

using System.Globalization;
namespace JwtAuthApp.JWT
{
    public class JwtConfiguration
    {
        public string Issuer { get; } = string.Empty;
        public string Secret { get; } = string.Empty;
        public string Audience { get; } = string.Empty;
        public int ExpireDays { get; }

        public JwtConfiguration(IConfiguration configuration)
        {
            var section = configuration.GetSection("JWT");
            Issuer = section[nameof(Issuer)];
            Secret = section[nameof(Secret)];
            Audience = section[nameof(Audience)];
            ExpireDays = Convert.ToInt32(section[nameof(ExpireDays)], CultureInfo.InvariantCulture);
        }
    }
}

4.4 将 JWT 配置添加到您的 appsettings.json 中

{
  "Jwt": {
    "Issuer": "JwtAuthApp",
    "Audience": "https://localhost:7031/",
    "Secret": "70FC177F-3667-453D-9DA1-AF223DF6C014",
    "ExpireDays": 30
  }
}

4.5 为 Configuration 配置 DIProgram.cs

builder.Services.AddTransient<JwtConfiguration>();

4.6 配置 JWT 身份验证扩展

using Microsoft.AspNetCore.Authentication;
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.AspNetCore.DataProtection;
using Microsoft.IdentityModel.Tokens;
using System;
using System.Text;

namespace JwtAuthApp.JWT
{
    public static class JwtAuthBuilderExtensions
    {
        public static AuthenticationBuilder AddJwtAuthentication(this IServiceCollection services, IConfiguration configuration)
        {
            var jwtConfiguration = new JwtConfiguration(configuration);
            services.AddAuthorization();
            return services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
                .AddJwtBearer(options =>
                {
                    options.SaveToken = true;
                    options.TokenValidationParameters = new TokenValidationParameters
                    {
                        ValidateIssuer = true,
                        ValidateAudience = true,
                        ValidateLifetime = true,
                        ValidateIssuerSigningKey = true,
                        ValidIssuer = jwtConfiguration.Issuer,
                        ValidAudience = jwtConfiguration.Audience,
                        IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtConfiguration.Secret)),
                        ClockSkew = TimeSpan.Zero
                    };
                    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;
                        }
                    };
                });
        }
    }
}

4.7 在 Program.cs 配置

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
builder.Services.AddControllers();
builder.Services.AddJwtAuthentication(builder.Configuration);

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.Run();

4.8 创建 Token 生成服务

using Microsoft.IdentityModel.Tokens;
using System.IdentityModel.Tokens.Jwt;
using System.Security.Claims;
using System.Text;

namespace JwtAuthApp.JWT
{
    public class TokenService
    {
        private readonly JwtConfiguration _config;

        public TokenService(JwtConfiguration config)
        {
            _config = config;
        }

        public string GenerateToken(string userId, string email)
        {
            var claims = new[]
            {
                new Claim(JwtRegisteredClaimNames.Sub, userId),
                new Claim(JwtRegisteredClaimNames.Email, email)
            };

            var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_config.Secret));
            var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);

            var token = new JwtSecurityToken(
                issuer: _config.Issuer,
                audience: _config.Audience,
                claims: claims,
                expires: DateTime.Now.AddDays(_config.ExpireDays),
                signingCredentials: creds
            );

            return new JwtSecurityTokenHandler().WriteToken(token);
        }
    }
}

4.9 注册 Token Service

builder.Services.AddTransient<TokenService>();

4.10 添加登录端点或控制器

app.MapPost("/login", [FromBody] LoginRequest request, TokenService tokenService)
{
    if (request.Username == "admin" && request.Password == "admin")
    {
        var userId = "123456"; // 从数据库获取用户 ID
        var email = "admin@example.com"; // 从数据库获取用户邮箱
        var token = tokenService.GenerateToken(userId, email);
        return Results.Ok(new { token });
    }

    return Results.Unauthorized();
})
.WithName("Login")
.RequireAuthorization();

4.11 新增 SwaggerConfiguration(方便测试)

using Microsoft.OpenApi.Models;
using Swashbuckle.AspNetCore.SwaggerGen;

namespace JwtAuthApp.JWT
{
    public static class SwaggerConfiguration
    {
        public static void Configure(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>()
                }
            });
        }
    }
}

4.12 添加 AppUser

 
public class AppUser : ClaimsPrincipal
    { 

        public AppUser(IHttpContextAccessor contextAccessor) : base(contextAccessor.HttpContext.User) { }

        public string UserID => FindFirst(CustomerConst.UserID)?.Value ?? "";

        public string OpenId => FindFirst(CustomerConst.OpenId)?.Value ?? ""; 

    }

builder.Services.AddHttpContextAccessor();
builder.Services.AddTransient<AppUser>();

4.13 为所有 Controller 或端点添加 Authorize 属性

app.MapGet("/weatherforecast", [Authorize] () =>
{
    // ...
})
.WithName("GetWeatherForecast")
.WithOpenApi();

app.MapGet("/user", [Authorize] (AppUser user) =>
{
    return Results.Ok(new { user.Email });
})
.WithName("GetUserEmail")
.WithOpenApi();

五、测试

  • 所有端点
  • 获取天气预报在登录前收到错误 401 (未授权)
  • 登录返回的 jwt 令牌
  • Swagger Auth 中使用 jwt 令牌
  • 获取天气预报返回结果
  • 获取用户电子邮件 返回用户电子邮件

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

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

【R语言】主成分分析与因子分析

一、主成分分析 主成分分析&#xff08;Principal Component Analysis, PCA&#xff09;是一种常用的无监督数据降维技术&#xff0c;广泛应用于统计学、数据科学和机器学习等领域。它通过正交化线性变换将&#xff08;高维&#xff09;原始数据投影到一个新的坐标系&#xff…

linux下pip下载项目失败

想下载CLIP的项目复现代码的时候&#xff0c;出现问题如下&#xff1a; 于是手动使用 Git 克隆仓库&#xff0c; git clone https://github.com/openai/CLIP.git cd CLIP pip install .ls查看文件如下&#xff1a;(手动克隆git项目成功)

Windows桌面系统管理8:项目实施

Windows桌面系统管理0&#xff1a;总目录-CSDN博客 Windows桌面系统管理1&#xff1a;计算机硬件组成及组装-CSDN博客 Windows桌面系统管理2&#xff1a;VMware Workstation使用和管理-CSDN博客 Windows桌面系统管理3&#xff1a;Windows 10操作系统部署与使用-CSDN博客 Wi…

【JavaScript】实战案例-放大镜效果、图片切换

目录 实现这种图片切换的和放大镜的效果&#xff1a; 第一步&#xff1a;图片的切换 第二步&#xff1a;鼠标经过中等盒子&#xff0c;显示隐藏大盒子 第三步&#xff1a;黑色遮罩盒子跟着鼠标来移动 遮罩层盒子移动的坐标&#xff1a; 总结一下~本章节对我有很大的收获…

windows使用clion运行lua文件,并且使用cjson

需要文件&#xff1a;clion&#xff0c;lua-5.4.2_Win64_bin&#xff0c;lua-5.4.2_Win64_dllw6_lib&#xff0c;lua-cjson-2.1.0.9&#xff0c;mingw64 1&#xff0c;下载安装clion。 2&#xff0c;下载lua windows运行程序 lua官网&#xff1a;http://www.lua.org/download…

人工智能基础之数学基础:01高等数学基础

函数 极限 按照一定次数排列的一列数:“&#xff0c;“,…,"…&#xff0c;其中u 叫做通项。 对于数列{Un}如果当n无限增大时&#xff0c;其通项无限接近于一个常数A&#xff0c;则称该数列以A为极限或称数列收敛于A&#xff0c;否则称数列为发散&#xff0c; 极限值 左…

flink-cdc同步数据到doris中

1 创建数据库和表 1.1 数据库脚本 -- 创建数据库eayc create database if not exists ods_eayc; -- 创建数据表2 数据同步 2.1 flnk-cdc 参考Flink CDC实时同步MySQL到Doris Flink CDC 概述 2.1.1 最简单的单表同步 从下面的yml脚本可以看到&#xff0c;并没有doris中创建…

CUDA兼容NVIDA版本关系

CUDA组成 兼容原则 CUDA 驱动(libcuda.so)兼容类型要求比CUDA新向后兼容无主版本一致&#xff0c;子版本旧兼容需要SASS、NVCC比CUDA老向前兼容提取对应兼容包 向后兼容&#xff1a;新版本支持旧版本的内容&#xff0c;关注的是新版本能否处理旧版本的内容。 向前兼容&#…

要配置西门子G120AX变频器实现**端子启停**和**Modbus RTU(485)频率给定

要配置西门子G120AX变频器实现端子启停和Modbus RTU&#xff08;485&#xff09;频率给定&#xff0c;需调整以下关键参数&#xff1a; 1. 端子启停控制 P29652[0]&#xff1a;设置启停信号源 &#xff08;例&#xff1a;P29652 [0] 722.0 表示用DI0端子作为启动/停止信号&…

撕碎QT面具(3):解决垂直布局的内容显示不全

问题&#xff1a;内容显示不全 解决方案&#xff1a;增加Vertical Spacer&#xff0c;它会把Group Box控件挤上去&#xff0c;让内容显示完全。 结果展示&#xff1a;

LabVIEW 中的 ax - events.llb 库

ax - events.llb 库位于C:\Program Files (x86)\National Instruments\LabVIEW 2019\vi.lib\Platform目录&#xff0c;它是 LabVIEW 平台下与特定事件处理相关的重要库。该库为 LabVIEW 开发者提供了一系列工具&#xff0c;用于有效地处理和管理应用程序中的各种事件&#xff0…

Macos机器hosts文件便捷修改工具——SwitchHosts

文章目录 SwitchHosts软件下载地址操作添加方案切换方案管理方案快捷键 检测 SwitchHosts SwitchHosts 是一款 Mac 平台上的免费软件&#xff0c;它可以方便地管理和切换 hosts 文件&#xff0c;支持多种 hosts 文件格式。 软件下载地址 SwitchHosts 操作 添加方案 添加 …

【算法】双指针(下)

目录 查找总价格为目标值的两个商品 暴力解题 双指针解题 三数之和 双指针解题(左右指针) 四数之和 双指针解题 双指针关键点 注意事项 查找总价格为目标值的两个商品 题目链接&#xff1a;LCR 179. 查找总价格为目标值的两个商品 - 力扣&#xff08;LeetCode&#x…

嵌入式linux利用标准字符驱动模型控制多个设备方法

一、驱动模型概述 Linux标准字符设备驱动模型基于以下核心组件: 设备号:由主设备号(Major)和次设备号(Minor)组成 cdev结构体:表征字符设备的核心数据结构 文件操作集合:file_operations结构体定义设备操作 sysfs接口:提供用户空间设备管理能力 传统单设备驱动与多设…

【可实战】Linux 常用统计命令:排序sort、去重uniq、统计wc

在 Linux 系统中&#xff0c;有一些常用的命令可以用来收集和统计数据。 一、常用统计命令的使用场景 日志分析和监控&#xff1a;通过使用 Linux 统计命令&#xff0c;可以实时监控和分析系统日志文件&#xff0c;了解系统的运行状况和性能指标。例如&#xff0c;使用 tail 命…

在 macOS 的 ARM 架构上按住 Command (⌘) + Shift + .(点)。这将暂时显示隐藏文件和文件夹。

在 macOS 的 ARM 架构&#xff08;如 M1/M2 系列的 Mac&#xff09;上&#xff0c;设置 Finder&#xff08;访达&#xff09;来显示隐藏文件夹的步骤如下&#xff1a; 使用快捷键临时显示隐藏文件&#xff1a; 在Finder中按住 Command (⌘) Shift .&#xff08;点&#xff…

分享一个解梦 Chrome 扩展 —— 周公 AI 解梦

一、插件简介 周公 AI 解梦是一款基于 Chrome 扩展的智能解梦工具&#xff0c;由灵机 AI 提供技术支持。它能运用先进的 AI 技术解析梦境含义&#xff0c;为用户提供便捷、智能的解梦服务。无论你是对梦境充满好奇&#xff0c;还是想从梦境中获取一些启示&#xff0c;这款插件都…

Git命令行入门

诸神缄默不语-个人CSDN博文目录 之前写过一篇VSCode Git的博文&#xff1a;VSCode上的Git使用手记&#xff08;持续更新ing…&#xff09; 现在随着开发经历增加&#xff0c;感觉用到命令行之类复杂功能的机会越来越多了&#xff0c;所以我专门再写一篇Git命令行的文章。 G…

【时时三省】(C语言基础)用N-S流程图表示算法

山不在高&#xff0c;有仙则名。水不在深&#xff0c;有龙则灵。 ----CSDN 时时三省 N-S流程图 既然用基本结构的顺序组合可以表示任何复杂的算法结构&#xff0c;那么&#xff0c;基本结构之间的流程线就是多余的了。1973年&#xff0c;美国学者I.Nassi和B .Shneiderman提出…

单元测试junit5

一、idea 安装自动化生成插件jcode5 安装可能不成功&#xff0c;尝试多次安装&#xff1b; 安装成功后&#xff0c;重启idea&#xff0c;再次确认安装是否成功&#xff1b; 二、在需要生成单元测试代码的模块的pom中引入依赖 ......<parent><groupId>org.springf…