Asp.Net Core 5 REST API 使用 JWT 身份验证 - Step by Step(二)

翻译自 Mohamad Lawand 2021年1月22日的文章 《Asp Net Core 5 Rest API Authentication with JWT Step by Step》 [1]

在本文中,我将向您展示如何向我们的 Asp.Net Core REST API 添加 JWT 身份验证。

我们将介绍的主题包含注册、登录功能以及如何使用 JWT (Json Web Tokens)[2]和 Bearer 身份验证。

你也可以在 YouTube 上观看完整的视频[3],还可以下载源代码[4]

这是 API 开发系列的第二部分,本系列还包含:

  • Part 1:Asp.Net Core 5 REST API - Step by Step

  • Part 3:Asp Net Core 5 REST API 中使用 RefreshToken 刷新 JWT - Step by Step

我们将基于上一篇文章中创建的 Todo REST API 应用程序进行当前的讲述,您可以通过阅读上一篇文章并与我一起构建应用程序,或者可以从 github 下载上一篇中的源代码。

前一篇文章中的代码准备好以后,就让我们开始本文吧。

首先,我们需要安装一些依赖包以使用身份验证:

dotnet add package Microsoft.AspNetCore.Authentication.JwtBearer 
dotnet add package Microsoft.AspNetCore.Identity.EntityFrameworkCore 
dotnet add package Microsoft.AspNetCore.Identity.UI

然后,我们需要更新 appsettings.json,在 appsettings 中添加 JWT 的设置部分,在该设置中添加一个 JWT secret(密钥)。

"JwtConfig": {"Secret" : "ijurkbdlhmklqacwqzdxmkkhvqowlyqa"
},

为了生成 secret,我们可以使用一个免费的 Web 工具(https://www.browserling.com/tools/random-string)来生成一个随机的 32 个字符的字符串。

我们在 appsettings 中添加完随机生成的 32 个字符的字符串后,接着需要在根目录中创建一个名为 Configuration 的新文件夹。

在这个 Configuration 文件夹中,我们将创建一个名为 JwtConfig 的新类:

public class JwtConfig
{public string Secret { get; set; }
}

现在我们需要更新 Startup 类,在 ConfigureServices 方法内,我们需要添加以下内容,以便将 JWT 配置注入到应用程序中:

services.Configure<JwtConfig>(Configuration.GetSection("JwtConfig"));

将这些配置添加到我们的 Startup 类中,即可在 Asp.Net Core 中间件和 IoC 容器中注册配置。

下一步是在我们的 Startup 类中添加和配置身份验证,在我们的 ConfigureServices 方法中,我们需要添加以下内容:

// 在本段中,我们将配置身份验证并设置默认方案
services.AddAuthentication(options => {options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;options.DefaultScheme = JwtBearerDefaults.AuthenticationScheme;options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
})
.AddJwtBearer(jwt => {var key = Encoding.ASCII.GetBytes(Configuration["JwtConfig:Secret"]);jwt.SaveToken = true;jwt.TokenValidationParameters = new TokenValidationParameters {ValidateIssuerSigningKey = true, //这将使用我们在 appsettings 中添加的 secret 来验证 JWT token 的第三部分,并验证 JWT token 是由我们生成的IssuerSigningKey = new SymmetricSecurityKey(key), //将密钥添加到我们的 JWT 加密算法中ValidateIssuer = false,ValidateAudience = false,ValidateLifetime = true,RequireExpirationTime = false};
});services.AddDefaultIdentity<IdentityUser>(options => options.SignIn.RequireConfirmedAccount = true).AddEntityFrameworkStores<ApiDbContext>();

更新好 ConfigureServices 之后,我们需要更新 Configure 方法,添加身份验证:

app.UseAuthentication();

配置添加完成后,我们需要构建应用程序,检查是否所有的内容都可以正常构建:

dotnet build
dotnet run

下一步是更新我们的 ApiDbContext,以便使用 Asp.Net 为我们提供的身份提供程序,导航到 Data 文件夹中的ApiDbContext,然后按以下内容更新 ApiDbContext 类:

public class ApiDbContext : IdentityDbContext

通过从 IdentityDbContext 而不是 DbContext 继承,EntityFramework 将知道我们正在使用身份验证,并且将为我们构建基础设施以使用默认身份表。

要在我们的数据库中生成身份表,我们需要准备迁移脚本并运行它们。也就是说,我们需要在终端中输入并运行以下命令:

dotnet ef migrations add "Adding authentication to our Api"
dotnet ef database update

迁移完成后,我们可以使用 Dbeaver 打开数据库 app.db,我们可以看到 EntityFramework 已经为我们创建了身份表。

下一步是设置控制器并为用户构建注册流程。我们需要在 Controllers 文件夹中创建一个新的控制器,并创建对应的 DTO 类(Data Transfer Objects)。

先在根目录中的 Configuration 文件夹中添加一个名为 AuthResult 的类:

// Configuration\AuthResult.cspublic class AuthResult
{public string Token { get; set; }public bool Success { get; set; }public List<string> Errors { get; set; }
}

然后我将添加一些文件夹来组织 DTOs,在 Models 文件夹中添加一个名为 DTOs 的文件夹,然后在此文件夹中创建两个子文件夹 Requests 和 Responses

我们需要添加供我们在控制器中的注册 Action 使用的 UserRegistrationDto。导航到 Models/DTO/Requests,添加一个新类 UserRegistrationDto

// Models\DTOs\Requests\UserRegistrationDto.cspublic class UserRegistrationDto
{[Required]public string Username { get; set; }[Required][EmailAddress]public string Email { get; set; }[Required]public string Password { get; set; }
}

添加 RegistrationResponse 响应类。

// Models\DTOs\Responses\RegistrationResponse.cspublic class RegistrationResponse : AuthResult
{}

现在,我们需要添加用户注册控制器,在控制器文件夹中添加一个新类,命名为 AuthManagementController,并使用以下代码更新它:

// Controllers\AuthManagementController.cs[Route("api/[controller]")] // api/authmanagement
[ApiController]
public class AuthManagementController : ControllerBase
{private readonly UserManager<IdentityUser> _userManager;private readonly JwtConfig _jwtConfig;public AuthManagementController(UserManager<IdentityUser> userManager, IOptionsMonitor<JwtConfig> optionsMonitor){_userManager = userManager;_jwtConfig = optionsMonitor.CurrentValue;}[HttpPost][Route("Register")]public async Task<IActionResult> Register([FromBody] UserRegistrationDto user){// 检查传入请求是否有效if(ModelState.IsValid){// 检查使用相同电子邮箱的用户是否存在var existingUser = await _userManager.FindByEmailAsync(user.Email);if(existingUser != null){return BadRequest(new RegistrationResponse(){Errors = new List<string>() {"Email already in use"},Success = false});}var newUser = new IdentityUser() { Email = user.Email, UserName = user.Username };var isCreated = await _userManager.CreateAsync(newUser, user.Password);if(isCreated.Succeeded){var jwtToken =  GenerateJwtToken( newUser);return Ok(new RegistrationResponse() {Success = true,Token = jwtToken});} else {return BadRequest(new RegistrationResponse(){Errors = isCreated.Errors.Select(x => x.Description).ToList(),Success = false});}}return BadRequest(new RegistrationResponse(){Errors = new List<string>() {"Invalid payload"},Success = false});}private string GenerateJwtToken(IdentityUser user){//现在,是时候定义 jwt token 了,它将负责创建我们的 tokensvar jwtTokenHandler = new JwtSecurityTokenHandler();// 从 appsettings 中获得我们的 secret var key = Encoding.ASCII.GetBytes(_jwtConfig.Secret);// 定义我们的 token descriptor// 我们需要使用 claims (token 中的属性)给出关于 token 的信息,它们属于特定的用户,// 因此,可以包含用户的 Id、名字、邮箱等。// 好消息是,这些信息由我们的服务器和 Identity framework 生成,它们是有效且可信的。var tokenDescriptor = new SecurityTokenDescriptor{Subject = new ClaimsIdentity(new []{new Claim("Id", user.Id), new Claim(JwtRegisteredClaimNames.Email, user.Email),new Claim(JwtRegisteredClaimNames.Sub, user.Email),// Jti 用于刷新 token,我们将在下一篇中讲到new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString())}),// token 的过期时间需要缩短,并利用 refresh token 来保持用户的登录状态,// 不过由于这只是一个演示应用,我们可以对其进行延长以适应我们当前的需求Expires = DateTime.UtcNow.AddHours(6),// 这里我们添加了加密算法信息,用于加密我们的 tokenSigningCredentials = new SigningCredentials(new SymmetricSecurityKey(key), SecurityAlgorithms.HmacSha256Signature)};var token = jwtTokenHandler.CreateToken(tokenDescriptor);var jwtToken = jwtTokenHandler.WriteToken(token);return jwtToken;}
}

添加完注册的 Action 后,我们可以在 Postman 中对其进行测试并获得 JWT token。

接下来是创建用户登录请求:

// Models\DTOs\Requests\UserLoginRequest.cspublic class UserLoginRequest
{[Required][EmailAddress]public string Email { get; set; }[Required]public string Password { get; set; }
}

然后,我们需要在 AuthManagementController 中添加 Login 方法:

[HttpPost]
[Route("Login")]
public async Task<IActionResult> Login([FromBody] UserLoginRequest user)
{if(ModelState.IsValid){// 检查使用相同电子邮箱的用户是否存在var existingUser = await _userManager.FindByEmailAsync(user.Email);if(existingUser == null) {// 出于安全原因,我们不想透露太多关于请求失败的信息return BadRequest(new RegistrationResponse(){Errors = new List<string>() {"Invalid login request"},Success = false});}// 现在我们需要检查用户是否输入了正确的密码var isCorrect = await _userManager.CheckPasswordAsync(existingUser, user.Password);if(!isCorrect) {// 出于安全原因,我们不想透露太多关于请求失败的信息return BadRequest(new RegistrationResponse(){Errors = new List<string>() {"Invalid login request"},Success = false});}var jwtToken = GenerateJwtToken(existingUser);return Ok(new RegistrationResponse() {Success = true,Token = jwtToken});}return BadRequest(new RegistrationResponse(){Errors = new List<string>() {"Invalid payload"},Success = false});
}

现在,我们可以在 Postman 中对其进行测试,我们将会看到 JWT token 已经成功生成。

下一步是保护我们的控制器,需要做的就是向控制器添加 Authorize 属性。

[Authorize(AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme)]
[Route("api/[controller]")] // api/todo
[ApiController]
public class TodoController : ControllerBase

此时,如果我们再对 Todo 进行测试,则由于未获得授权,我们将会无法执行任何请求。为了发送带授权的请求,我们需要添加带有 Bearer token 的授权 Header,以便 Asp.Net 可以验证它,并授予我们执行操作的权限。

译者注:
添加 Bearer token 请求头的方法是:在 Headers 中,添加一个名称为 Authorization 的 Header 项,值为 Bearer <token>(需将 <token> 替换为真实的 token 值)。使用 Postman 测试时,可参考 Postman 官方文档:https://learning.postman.com/docs/sending-requests/authorization/#bearer-token。

至此,我们已经完成了使用 JWT 为 REST API 添加身份验证的功能。

感谢您花时间阅读本文。

本文是 API 开发系列的第二部分,本系列还包含:

  • Part 1:Asp.Net Core 5 REST API - Step by Step

  • Part 3:Asp Net Core 5 REST API 中使用 RefreshToken 刷新 JWT - Step by Step


相关链接:

  1. https://dev.to/moe23/asp-net-core-5-rest-api-authentication-with-jwt-step-by-step-140d Asp Net Core 5 Rest API Authentication with JWT Step by Step ↩︎

  2. https://mp.weixin.qq.com/s/jnC8FDKm0Srj0ww-EvdUiw JWT 介绍 - Step by Step ↩︎

  3. https://youtu.be/LgpC4tYtc6Y ↩︎

  4. https://github.com/mohamadlawand087/v7-RestApiNetCoreAuthentication ↩︎

作者 :Mohamad Lawand
译者 :技术译民
出品 :技术译站(https://ITTranslator.cn/)

END

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

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

相关文章

掌握这四点核心思想,统计学才算入门

在日常生活中&#xff0c;统计无处不在&#xff0c;比如最常见的问卷调查。实际上&#xff0c;统计学作为一门研究数据收集、整理与分析的学科&#xff0c;是能够帮助我们实现数据运用的终极目标&#xff08;终极目标&#xff1a;洞悉本质、确定规律、预测未来&#xff09;。但…

NET问答: Log4Net 无法将日志写入到 log 文件的求助.....

咨询区 john84&#xff1a;我在一个小项目中用上了 Log4Net&#xff0c;程序跑起来后没有任何日志写入到 log 文件&#xff0c;可能是我的 log appender 配的有问题&#xff0c;尴尬????&#xff0c;大家看看我这样配的有问题吗&#xff1f;web.config 完整的配置如下。<…

centos php.ini redis,CentOS下安装Redis及Redis的PHP扩展

1、安装Redis1.1 如果没有安装wget&#xff0c;安装wgetyum install wgetwget http://download.redis.io/releases/redis-3.2.0.tar.gz1.3 解压&#xff0c;并进入解压目录进行编译。编译成功后会在redis-3.2.0目录下生成相关文件$ tar xzf redis-3.2.0.tar.gz$ cd redis-3.2.0…

荐书 | 从启蒙到进阶,值得推荐的五本少儿编程

据小木对身边的人了解&#xff0c;好像码农们都有这么一个愿望&#xff1a;等我有孩子了&#xff0c;我一定教我的孩子学编程。玩游戏玩自己设计的才酷&#xff01;看着一个个码农爸爸憧憬着美好的愿景&#xff0c;小木恨不得马上帮他们实现这个愿望。这不~在了解了许多本儿童编…

ASP.NET Core 5.0 Web API 自动集成Swashbuckle

ASP.NET Core 5.0 Web API与开放源代码项目 Swashbuckle.AspNetCore 的维护人员合作&#xff0c;ASP.NET Core API 模板包含对 Swashbuckle 的 NuGet 依赖关系。Swashbuckle 是一个常用的开放源代码 NuGet 包&#xff0c;可动态发出 OpenAPI 文档。Swashbuckle 通过 API 控制器…

卷积神经网络「失陷」,CoordConv来填坑

卷积神经网络拥有权重共享、局部连接和平移等变性等非常优秀的属性&#xff0c;使其在多种视觉任务上取得了极大成功。但在涉及坐标建模的任务上&#xff08;如目标检测、图像生成等&#xff09;&#xff0c;其优势反而成为了缺陷&#xff0c;并潜在影响了最终的模型性能。Uber…

WPF 对控件截图

突然需要一个Logo,找又找不到&#xff0c;就自己做喽&#xff0c;首先想到的是ps,简单方便&#xff0c;转念一想&#xff0c;wpf搞这个不是很简单么&#xff1f;直接弄做好&#xff0c;截图一下不就行了。。。开工了&#xff0c;先在iconfont上找了个图标&#xff1a;是这样的然…

福利来袭,送你105例C语言实战

前几周&#xff0c;TIOBE 编程语言社区最新发布了 2018 年 6 月排行榜&#xff0c;和5月份相比&#xff0c;C语言的增长率达到8.09%&#xff0c;是排行前20编程语言中增长率最大的&#xff0c;可见学C语言的人越来越多。小编一直有意识地收集了一些编程语言的实战例子&#xff…

关于c/c++/obj-c的混合使用 (2010-06-22 10:05:33)

关于c/c/obj-c的混合使用 (2010-06-22 10:05:33)转载标签&#xff1a; 杂谈分类&#xff1a; iPhone开发1&#xff09;obj-c的编译器处理后缀为m的文件时&#xff0c;可以识别obj-c和c的代码&#xff0c;处理mm文件可以识别obj-c,c,c代码&#xff0c;但cpp文件必须只能用 c/c代…

你知道WPF这三大模板实例运用吗?

1、介绍对于Windows桌面端应用开发来讲&#xff0c;WPF以其界面渲染的特殊性&#xff0c;灵活的界面布局而让人津津乐道&#xff0c;因为它能为用户提供更好的交互体验。如何利用WPF开发出让人赏心悦目的界面与功能呢&#xff1f;这里不仅仅只是布局的功劳&#xff0c;很大一部…

如何判断程序员是在装逼还是有真本事?

程序员是一个十分特殊的群体&#xff0c;他们十分内敛、腼腆&#xff0c;但是只要一开口就能判断出来&#xff0c;到底是在装逼还是有真本事&#xff0c;不信咱们往下看&#xff01;1、这个功能是小case&#xff0c;分分钟搞定一般情况下&#xff0c;程序员在拿到一个新的功能需…

怎样借助Python爬虫给宝宝起个好名字

Beginning每个人一生中都会遇到一件事情&#xff0c;在事情出现之前不会关心&#xff0c;但是事情一旦来临就发现它极其重要&#xff0c;并且需要在很短的时间内做出重大决定&#xff0c;那就是给自己的新生宝宝起个名字。因为要在孩子出生后两周内起个名字&#xff08;需要办理…

CAP-分布式事务的解决方案

CAP 是一个基于 .NET Standard 的 C# 库&#xff0c;它是一种处理分布式事务的解决方案&#xff0c;同样具有 EventBus 的功能&#xff0c;它具有轻量级、易使用、高性能等特点。https://github.com/dotnetcore/CAP在我们构建 SOA 或者 微服务系统的过程中&#xff0c;我们通常…

我是怎么用机器学习技术找到女票的

机器学习在我们生活中的用处有多大&#xff0c;就不用我们多说了&#xff0c;大到医疗诊断&#xff0c;小到手机应用&#xff0c;机器学习都应用的风风火火。但是用机器学习帮自己在学校找对象&#xff0c;你听说过吗?最近滑铁卢大学一位叫 Bai Li 的留学生(李白?应是中国同胞…

php 重定向数据不丢失,PHP重定向如何实现数据不丢失?

PHP重定向如何实现数据不丢失&#xff1f;首先获取要保存的数据&#xff1b;$data [username > guanhuicoder,redirect_url > ./index.phpemail > guanhuicodercode.com];然后将数据转为JSON字符串&#xff0c;并将其储存在Session中&#xff1b;$data [username &g…

北大教授郑也夫斗胆谈了7个天大的问题(非常狠,也很现实)

我是一个小人物&#xff0c;今天斗胆谈一个天大的问题——中国教育。中国教育是一个天大的问题&#xff0c;不是说我们有多大的本领把它办得多么好&#xff0c;而是我们居然可以把它办得这样糟&#xff0c;这是一个很沉痛的话题。——北大教授、社会学家郑也夫1不输在起跑线&am…

.NET 6 Preview 3 中 ASP.NET Core 的更新和改进

原文&#xff1a;bit.ly/2Qb56NP作者&#xff1a;Daniel Roth译者&#xff1a;精致码农-王亮.NET 6 预览版 3 现已推出&#xff0c;其中包括许多对新的 ASP.NET Core 改进。以下是本次预览版的新内容&#xff1a;更小的 SignalR、Blazor Server、MessagePack 脚本文件启用 Redi…

php 图片消除锯齿,ps如何消除边缘锯齿

PS消除边缘锯齿的方法&#xff1a;打开图片选择魔棒工具&#xff0c;在窗口中解锁图层然后将鼠标移动到背景区域&#xff0c;左键单击它再按删除键&#xff0c;然后再右键点击人像&#xff0c;选择羽化&#xff0c;将羽化半径设置为4&#xff0c;点击确定后按删除键&#xff0c…

C#如何在Windows中操作IIS设置FTP服务器

什么是FTPFTP(File Transfer Protocol)是TCP/IP网络上两台计算机传送文件的协议&#xff0c;使得主机间可以共享文件.可以将 Internet 信息服务 (IIS) 配置为作为 FTP 服务器来运行。 这样&#xff0c;其他计算机便可以连接到服务器并将文件复制到服务器或者从服务器复制文件。…

这是一份编程宝典,请查收!

最近&#xff0c;小编一直在整理有关编程的书籍&#xff0c;有Android、C、Java、PHP、木马、算法等类型的书籍。现在&#xff0c;小编准备将这些资料免费分享给大家&#xff01;Android应用开发入门教程&#xff08;经典版&#xff09;易学CC语言解惑HTML入门教程Java解惑&…