.NET 8 集成 JWT Bearer Token

注意:这是一种非常简单且不是最低限度安全的设置 JWT 的方法。

步骤 1——安装软件包

首先,您需要安装一些 NuGet 包。

dotnet add package Microsoft.AspCore.Authentication.JwtBearer
dotnet add package System.IdentityModel.Tokens.Jwt

步骤 2——创建类

你需要创建一些类来处理登录请求、注册请求和授权响应。你还需要某种类型的用户。

using System.ComponentModel.DataAnnotations;

namespace Auth;

public class LoginRequest
{
[Required]
[EmailAddress]
public string Email { get; set; }

    [Required]
public string Password { get; set; }
}

using System.ComponentModel.DataAnnotations;

namespace Auth;

public class RegistrationRequest
{
[Required]
public string UserID { get; set; }

    [Required]
public string Username { get; set; }

    [Required]
public string Firstname { get; set; }

    [Required]
public string Lastname { get; set; }

    [Required]
[EmailAddress]
public string Email { get; set; }

    [Required]
public string Password { get; set; }
}

namespace Auth;

public class AuthResponse
{
public string UserId { get; set; }
public string Username { get; set; }
public string Token { get; set; }
public string? ProfileImage { get; set; }
}

步骤 3——创建控制器

当我们创建了类之后,我们需要实现注册用户和登录的逻辑。我将跳过创建用户的逻辑,只在我的示例中使用我的服务,您需要自己做这件事。

[HttpPost("register")]
public async Task<IActionResult> Register([FromBody] RegistrationRequest request)
{
var salt = GenerateSalt();
var saltedPassword = request.Password + salt;

    var user = new User
{
Firstname = request.Firstname,
Lastname = request.Lastname,
Email = request.Email,
Password = _passwordHasher.HashPassword(null, saltedPassword),    // Null is because the user is not created yet, normally this is where the user object is.
Salt = salt,
Role = Enums.Role.USER
};

    await _userService.CreateUser(user);
var token = _tokenService.CreateToken(user);

    return Ok(new AuthResponse { Token = token });
}

[HttpPost("login")]
public async Task<IActionResult> Login([FromBody] LoginRequest request)
{
User? user = await _userService.FindByEmailAsync(request.Email);        

    if (user == null)
{
return Unauthorized("Invalid credentials 1");
}

    var saltedPassword = request.Password + user.Salt;

var result = _passwordHasher.VerifyHashedPassword(user, user.Password,saltedPassword);

    if (result != PasswordVerificationResult.Success)
{
return Unauthorized("Invalid credentials 2");
}

    // Generate token
var token = _tokenService.CreateToken(user);

    // Return the token
return Ok(new AuthResponse { Token = token });
}

步骤4 —创建令牌服务

现在我们需要创建一个生成 JWT 令牌的方法。在我们的令牌中,我们可以添加任意数量的索赔正如我们想要的那样。这里需要注意的是,我们的 SecurityTokenDescriptor 必须具有与“Program.cs”中的授权设置相同的令牌验证参数。我们稍后会再讨论这一点。我在这里使用的名为“_configuration”的变量,正是通过“IConfiguration”依赖注入到我的控制器中的。

public string CreateToken(User user)
{
var tokenHandler = new JwtSecurityTokenHandler();
var key = Encoding.ASCII.GetBytes(_configuration["Jwt:Key"]);
var tokenDescriptor = new SecurityTokenDescriptor
{
Subject = new ClaimsIdentity(new Claim[]
{
new Claim(ClaimTypes.NameIdentifier, user.UserID),
new Claim(ClaimTypes.Role, user.Role.ToString()),
// Add more claims as needed
}),
Expires = DateTime.UtcNow.AddHours(1),
SigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature),
Issuer = _configuration["Jwt:Issuer"], // Add this line
Audience = _configuration["Jwt:Audience"] 
};

    var token = tokenHandler.CreateToken(tokenDescriptor);
return tokenHandler.WriteToken(token);
}

步骤 5 — 设置 Swagger 配置

现在我们需要配置 Swagger,以便稍后测试我们的端点。这里需要注意的是,当我们在 Swagger 的授权输入框中输入令牌字符串时,需要依次输入:Bearer,后跟一个空格,然后是令牌字符串。

builder.Services.AddEndpointsApiExplorer();
builder.Services.AddSwaggerGen(c =>
{
c.SwaggerDoc("v1", new() { Title = "Pappa´s API", Version = "v1" });

    // Define the OAuth2.0 scheme that's in use (i.e., Implicit Flow)
c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
{
Description = "JWT Authorization header using the Bearer scheme. Example: \"Authorization: Bearer {token}\"",
Name = "Authorization",
In = ParameterLocation.Header,
Type = SecuritySchemeType.ApiKey,
Scheme = "Bearer"
});

    c.AddSecurityRequirement(new OpenApiSecurityRequirement()
{
{
new OpenApiSecurityScheme
{
Reference = new OpenApiReference
{
Type = ReferenceType.SecurityScheme,
Id = "Bearer"
},
Scheme = "oauth2",
Name = "Bearer",
In = ParameterLocation.Header,
},
new List<string>()
}
});
});

步骤 6——设置授权

这里重要的是,我们的令牌验证参数与我们在令牌服务中的“CreateToken”方法中添加的参数相同。

builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddJwtBearer(options =>
{
options.TokenValidationParameters = new TokenValidationParameters
{
ValidateIssuer = true,
ValidateAudience = true,
ValidateLifetime = true,
ValidateIssuerSigningKey = true,
ValidIssuer = builder.Configuration["Jwt:Issuer"],
ValidAudience = builder.Configuration["Jwt:Audience"],
IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(builder.Configuration["Jwt:Key"])),
ClockSkew = TimeSpan.Zero
};
});

步骤 7——设置中间件

我们放置中间件的顺序非常重要,所以不要弄错顺序。我们也指定 Swagger 仅在开发环境中有效。

if (app.Environment.IsDevelopment())
{
app.UseSwagger();
app.UseSwaggerUI();
}

app.UseHttpsRedirection();
app.UseRouting();
app.UseAuthorization();
app.MapControllers();

步骤 8 — 设置应用程序设置

现在我们需要将 JWT 值添加到我们的“apptsettings.json”文件中,包括密钥、颁发者和受众。出于演示和开发目的,我仅使用这些简单的值。但请注意,密钥尤其不应以纯文本形式存储,为了安全起见,最好将所有值存储在安全的地方,例如 Azure Secrets 或 GitHub Secrets。

"Jwt": {
"Key": "your_secret_key_here_your_secret_key_here",
"Issuer": "your_issuer",
"Audience": "your_audience"
}

步骤 9 — 在控制器中设置授权

现在是时候将我们的令牌集成到我们的某个 API 中了。为此,我们让 .NET 处理编码,就像我们在“Program.cs”文件中设置的那样。我们还添加了“[Authroize]”和“Roles”,以实现基于角色的身份验证。如果您想添加更多角色,只需在同一字符串中用逗号分隔它们即可。

[HttpGet("getuser")]
[Authorize(Roles = "USER")]
public async Task<ActionResult<User>> GetUser()
{
// Retrieve userId from the claims
var userIdClaim = User.Claims.FirstOrDefault(c => c.Type == ClaimTypes.NameIdentifier)?.Value;

Console.WriteLine("Claims received:");
foreach (var claim in User.Claims)
{
Console.WriteLine($"{claim.Type}: {claim.Value}");
}

        if(userIdClaim == null)
{
return Unauthorized("No user ID claim present in token.");
}

try
{
User? user = await _userService.GetUser(userIdClaim);
return Ok(user);
}
catch (InvalidOperationException ex)
{
return BadRequest(ex.Message);
}
}

关于.NET8集成JWT本文先介绍到这里了。

如果您喜欢此文章,请收藏、点赞、评论,谢谢,祝您快乐每一天。

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

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

相关文章

模型汇总-数学建模

一、优化模型1.线性规划线性规划&#xff08;Linear Programming, LP&#xff09;是一种数学优化方法&#xff0c;用于在给定的线性约束条件下&#xff0c;找到线性目标函数的最大值或最小值。它是运筹学中最常用的方法之一。线性规划的标准形式最大化问题标准形式&#xff1a;…

2025年09月计算机二级MySQL选择题每日一练——第十二期

计算机二级中选择题是非常重要的&#xff0c;本期是这个系列的最后一期了&#xff01; 答案及解析将在末尾公布&#xff01; 今日主题&#xff1a;综合应用进阶 1、设有如下创建表的语句&#xff1a; CREATE TABLE tb_test( ID INT NOT NULL PRIMARY KEY, sno CHAR(10) NOT …

计组(2)CPU与指令

一、总体认识CPU1、软硬件角度CPU&#xff0c;全称就是中央处理器。从硬件上来说&#xff0c;CPU是一个超大规模集成电路&#xff0c;通过电路实现加法、乘法乃至各种各样的处理逻辑。从软件来说&#xff0c;CPU就是一个执行各种计算机指令的逻辑机器。2、计算机指令所谓的计算…

用Java让家政服务触手可及

家政服务不仅仅包括日常保洁&#xff0c;随着社会的发展&#xff0c;从日常保洁、衣物清洁到家电维修、月嫂保姆&#xff0c;家政服务的场景越发多元。用户不仅追求服务的 “专业度”&#xff0c;更看重 “便捷性”—— 能否快速找到服务、预约服务、了解服务效果&#xff1f;上…

Python OpenCV图像处理与深度学习:Python OpenCV特征检测入门

特征检测与描述&#xff1a;探索图像中的关键点 学习目标 通过本课程&#xff0c;学员们将掌握特征检测的基本概念&#xff0c;了解如何使用OpenCV库中的SIFT和SURF算法进行特征点检测和特征描述符的计算。实验将通过理论讲解与实践操作相结合的方式&#xff0c;帮助学员深入理…

ECDH (椭圆曲线迪菲-赫尔曼密钥交换)

文章目录一、什么是ECDH&#xff1f;二、为什么需要 ECDH&#xff1f;要解决什么问题&#xff1f;三、原理与图示四、核心比喻&#xff1a;混合颜料五、技术实现步骤1. 约定公共参数2. 生成密钥对3. 交换公钥4. 计算共享密钥5. 密钥派生六、注意事项七、安全性基础八、优势特点…

Spring Boot实战:打造高效Web应用,从入门到精通

目录一、Spring Boot 初相识二、搭建开发环境2.1 安装 JDK2.2 安装 IDE&#xff08;以 IntelliJ IDEA 为例&#xff09;2.3 初始化 Spring Boot 项目三、Spring Boot 基础配置3.1 配置文件详解&#xff08;application.properties 和 application.yml&#xff09;3.2 自定义配置…

2025网络安全宣传周知识竞赛答题活动怎么做

网络安全答题PK小程序可以结合竞技性、趣味性和知识性&#xff0c;设计以下核心功能模块&#xff0c;提升用户参与度和学习效果&#xff1a;一、核心PK功能实时对战匹配 随机匹配在线用户&#xff08;按段位/积分相近原则&#xff09; 好友定向PK&#xff08;支持分享邀请对战&…

echo、seq、{}、date、bc命令

文章目录echo、seq、{}、date、bc命令echo案例seq命令案例{}花括号列表扩展序列扩展嵌套扩展datebc(高精度计算器)echo、seq、{}、date、bc命令 echo echo命令是一个常用的Shell命令&#xff0c;用于在终端上输出文本。它的基本语法如下&#xff1a; echo [option] [string]…

Vue2之Vuex

文章目录 数据准备新建项目选择模块安装vscode工具打开 删除无用文件删除src/assets文件下的所有内容删除src/components文件下的所有内容修改src/app.vuevscode运行项目 一、 概述1.是什么2. 使用场景3.优势4 Vuex流程图5.注意&#xff1a; 二、需求: 多组件共享数据创建三个组…

2025具身智能赛道观察:技术、产业与视频基础设施

引言 2025 年&#xff0c;具身智能&#xff08;Embodied Intelligence&#xff09;毫无疑问已经成为全球资本追逐的“风口赛道”。从人形机器人、无人配送&#xff0c;到低空经济和智能驾驶&#xff0c;几乎所有与物理世界深度结合的领域&#xff0c;都被纳入具身智能的广义范…

【商业银行风控模型(python版本,实操合集,附带anaconda安装教程,持续更新)】

Anaconda&#xff08;Python工具&#xff09;安装1.Mac中安装Anaconda2.点击“Free Download”下载后&#xff0c;点击“Skip registration”&#xff0c;跳过注册环节。 3.conda list4.安装完成Anaconda基本操作命令 # 查看当前虚拟环境下的所有包 conda list # 查看某个特定的…

FPGA DDR 地址映射-黄金法则

FPGA 中 DDR 控制器的地址映射顺序&#xff08;Address Mapping Order&#xff09; 是优化设计速度&#xff08;带宽和效率&#xff09; 的关键。简单来说&#xff0c;地址映射顺序决定了线性地址如何映射到 DDR 芯片内部的物理结构&#xff08;Bank、Row、Column&#xff09;。…

网络安全设备监控指标

网络安全设备监控指标 近日看到一篇设备情况汇报&#xff0c;内容写得有些欠缺&#xff0c;因此我特意问了一下AI&#xff0c;整理了一下思路。以下是监控需要关注的性能指标。权当抛砖引玉。根据指标可以做监控&#xff0c;也可以做调研指标。 业务承载能力 吞吐量&#xff08…

JSP程序设计之JSP指令

1、JSP指令概念与分类 &#xff08;1&#xff09;概念 JSP指令相当于在编译期间的命令&#xff0c;用来设置与整个JSP页面相关的属性&#xff0c;它并不直接产生任何可见的输出&#xff0c;用来设置全局变量、声明类、要实现的方法和输出内容的类型等。在JSP文件被解析为Java…

Generative Art with p5.js: Creating Beauty from Code

Are you ready to make something truly beautiful with p5.js? Forget about boring bar charts and sales data—let’s create art that moves, breathes, and responds to your touch. We’re going to explore generative art, where code becomes your paintbrush and a…

Wi-Fi技术——网络安全

一、数据帧的安全 1、无线网络安全的发展 理论上无线电波范围内的任何一个站点都可以监听并登录无线网络&#xff0c;所有发送或接收的数据&#xff0c;都有可能被截取&#xff0c;因此无线网络安全十分重要。 原始802.11的安全策略为WEP&#xff0c;其存在根本性的漏洞&#x…

Java提供高效后端支撑,Vue呈现直观交互界面,共同打造的MES管理系统,含完整可运行源码,实现生产计划、执行、追溯一站式管理,提升制造执行效率

前言在当今竞争激烈的制造业环境中&#xff0c;企业面临着提高生产效率、降低成本、保证产品质量以及快速响应市场变化等多重挑战。制造执行系统&#xff08;MES&#xff0c;Manufacturing Execution System&#xff09;作为连接企业上层计划管理系统&#xff08;如ERP&#xf…

【macOS】垃圾箱中文件无法清理的常规方法

【macOS】垃圾箱中文件无法清理的方法如果外接 SSD 移动盘上的垃圾文件无法删除&#xff0c; 可能是由于文件系统格式不兼容、文件被占用、权限不足等原因导致的&#xff0c; 以下是一些常见的解决方法&#xff1a;检查移动硬盘文件系统格式&#xff1a;如果移动硬盘是 NTFS 格…

鸿蒙ArkTS 核心篇-15-条件渲染(组件)

目录 根据逻辑条件结果&#xff0c;渲染不同的 UI 内容 DevEco Studio代码实战 预览效果 总结 根据逻辑条件结果&#xff0c;渲染不同的 UI 内容 DevEco Studio代码实战 let num: number 20Entry Component struct Index {build() {Column() {if (num 1) {Text(文本 1)} …