如何在 Net6.0 中对 WebAPI 进行 JWT 认证和授权

如何,net6,webapi,进行,jwt,认证,授权 · 浏览次数 : 2544

小编点评

**代码摘要** * 创建一个新的应用程序实例。 * 注册和配置中间件。 * 配置应用程序的授权配置逻辑。 * 配置应用程序的授权配置逻辑。 * 创建一个新的应用程序实例。 * 注册和配置中间件。 * 配置应用程序的授权配置逻辑。 * 创建一个新的应用程序实例。 * 注册和配置中间件。 * 配置应用程序的授权配置逻辑。 **关键代码** * `builder.Services.AddEndpointsApiExplorer()`:配置 API Explorer中间件。 * `builder.Services.AddSwaggerGen()`:配置 SwaggerGen中间件。 * `app.UseAuthentication()`:启用认证中间件。 * `app.UseAuthorization()`:启用授权中间件。 * `app.MapGet()``和`app.MapGet()`:配置中间件的路由。 * `CustomAuthorizeData`:自定义授权中间件接口。 **配置** * `appsettings.json` 中配置应用程序的授权配置。

正文

一、简介
    我们做微服务开发,或者说做分布式开发,有一项技术我们是避不开的,那就是WebAPI,在 Net6.0中,有两类 WebAPI,一类是极简 WebAPI,它砍掉了很多冗余的东西,更纯粹的是做 API的,也更适合做微服务的开发。另外一类就是我们通常使用的正常 API,这个没得说,也是我们使用最多的。
    我们开发的API必须做鉴权和授权操作,否则,就成了裸跑了,那对于系统来说是很危险的。总体来说,一般的WebAPI和MinimalAPI鉴权的过程都是差不多的,但是也有微小的差异。今天我们就来详细说一下,内容很简单,大家有了基础可以随意去扩展。

      开发环境详情:
          操作系统:Windows 10 Professional
          开发工具:Visual Studio 2022
          开发语言:C#
          开发平台:Asp.Net Core 6.0 WebAPI
          测试工具:PostMan

二、具体步骤
    我们在做具体的开发前,也要做一些准备工作,我们要做鉴权和授权,尤其是要使用 JWT 做鉴权和授权,这里面包含两个项目,一个是鉴权服务器,用于提供 JWTToken,另外一个项目是需要做鉴权和授权的具体 WebAPI 项目。有了准备,我们就可以开始了。

    1、第一个项目:PatrickLiu.Net6API.AuthenticationCenter,用于提供获取 Token 接口。
        

        (1)、Program.cs 源码如下,红色是重要代码:            

 1 using PatrickLiu.Net6API.Extensions;
 2 
 3 var builder = WebApplication.CreateBuilder(args);
 4 
 5 builder.Services.AddControllers();
 6 builder.Services.AddEndpointsApiExplorer();
 7 builder.Services.AddSwaggerGen();
 8 
 9 builder.Services.Configure<JWTTokenOption>(builder.Configuration.GetSection("JWTTokenOption"));
10 builder.Services.AddTransient<IJWTService, JWTService>();
11 
12 var app = builder.Build();
13 
14 app.UseSwagger();
15 app.UseSwaggerUI();
16 
17 app.MapControllers();
18 
19 app.Run();

          (2)、AuthenticationController 源码如下:

 1 using Microsoft.AspNetCore.Mvc;
 2 using Newtonsoft.Json;
 3 using PatrickLiu.Net6API.Extensions;
 4 
 5 namespace PatrickLiu.Net6API.AuthenticationCenter.Controllers
 6 {
 7     [ApiController]
 8     [Route("api/[controller]/[action]")]
 9     public class AuthenticationController : ControllerBase
10     {
11         private readonly IJWTService _jWTService;
12 
13         /// <summary>
14         /// 实例化。
15         /// </summary>
16         /// <param name="jWTService">注入服务。</param>
17         public AuthenticationController(IJWTService jWTService)
18         {
19             _jWTService = jWTService;
20         }
21 
22         /// <summary>
23         /// 根据用户名和密码获取 Token。
24         /// </summary>
25         /// <param name="userName">用户名。</param>
26         /// <param name="password">密码。</param>
27         /// <returns></returns>
28         [HttpPost]
29         public string Login(string userName, string password)
30         {
31             if (!string.IsNullOrEmpty(userName) && !string.IsNullOrEmpty(password))
32             {
33                 if (string.Compare(userName, "PatrickLiu", true) == 0 && string.Compare(password, "liulei123456", true) == 0)
34                 {
35                     string token = _jWTService.GetToken(userName, password);
36                     return JsonConvert.SerializeObject(new
37                     {
38                         Result = true,
39                         Token = token
40                     });
41                 }
42             }
43             return string.Empty;
44         }
45     }
46 }

          (3)、appsettings.json 配置文件源码如下,红色字体要注意:

 1 {
 2   "Logging": {
 3     "LogLevel": {
 4       "Default": "Information",
 5       "Microsoft.AspNetCore": "Warning"
 6     }
 7   },
 8   "AllowedHosts": "*",
 9   "JWTTokenOption": {
10     "Audience": "PatrickLiu.com",
11     "Issuer": "PatrickLiu.com",
12     "SecurityKey": "12333456677655ffrrffff"
13   }
14 }


    2、还有一个公共项目,用于存放公共类型。项目类型:PatrickLiu.Net6API.Extensions,项目类型:Net 6.0类库。
        

        (1)、IJWTService 源码如下:

 1 namespace PatrickLiu.Net6API.Extensions
 2 {
 3     /// <summary>
 4     /// 提供 Token 的服务。
 5     /// </summary>
 6     public interface IJWTService
 7     {
 8         /// <summary>
 9         /// 获取 Token。
10         /// </summary>
11         /// <param name="userName">用户名</param>
12         /// <param name="password">密码</param>
13         /// <returns></returns>
14         string GetToken(string userName,string password);
15     }
16 }

        (2)、JWTService 源码如下:      

 1 using Microsoft.Extensions.Options;
 2 using Microsoft.IdentityModel.Tokens;
 3 using System.IdentityModel.Tokens.Jwt;
 4 using System.Security.Claims;
 5 using System.Security.Cryptography;
 6 using System.Text;
 7 
 8 namespace PatrickLiu.Net6API.Extensions
 9 {
10     /// <summary>
11     /// 提供 Token 服务的实现。
12     /// </summary>
13     public sealed class JWTService : IJWTService
14     {
15         private readonly IOptionsMonitor<JWTTokenOption> _option;
16 
17         /// <summary>
18         /// 实例化。
19         /// </summary>
20         /// <param name="option">注入选项。</param>
21         public JWTService(IOptionsMonitor<JWTTokenOption> option)
22         {
23             _option = option;
24         }
25 
26         /// <summary>
27         ///  获取 Token。
28         /// </summary>
29         /// <param name="userName">用户名。</param>
30         /// <param name="password">密码</param>
31         /// <returns></returns>
32         public string GetToken(string userName, string password)
33         {
34             #region 有效载荷
35 
36             var claims = new[] {
37             new Claim(ClaimTypes.Name, userName),
38             new Claim("NickName",userName),
39             new Claim(ClaimTypes.Role,"Administrator"),
40             new Claim("Password",password),
41             };
42 
43             #endregion
44 
45             SymmetricSecurityKey key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_option.CurrentValue.SecurityKey!));
46 
47             SigningCredentials signingCredentials = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
48 
49             JwtSecurityToken token = new JwtSecurityToken(
50                 issuer: _option.CurrentValue.Issuer!,
51                 audience: _option.CurrentValue.Audience!,
52                 claims: claims,
53                 expires: DateTime.Now.AddMinutes(5),
54                 signingCredentials: signingCredentials
55                 );
56 
57             string returnToken = new JwtSecurityTokenHandler().WriteToken(token);
58 
59             return returnToken;
60         }
61     }
62 }

        (3)、JWTTokenOption 源码如下:

 1 namespace PatrickLiu.Net6API.Extensions
 2 {
 3     /// <summary>
 4     /// 用于接受配置数据实体类型。 
 5     /// </summary>
 6     public sealed class JWTTokenOption
 7     {
 8         /// <summary>
 9         /// 获取或者设置接受者。
10         /// </summary>
11         public string? Audience { get; set; }
12 
13         /// <summary>
14         /// 获取或者设置加密 key。
15         /// </summary>
16         public string? SecurityKey { get; set; }
17 
18         /// <summary>
19         /// 获取或者设置发布者
20         /// </summary>
21         public string? Issuer { get; set; }
22     }
23 }

        (4)、授权服务器运行起来如下:

          

          


    3、现在是普通WebAPI类型项目:

        (1)、我们先看一下项目截图,有一个直观感受,截图如下:
            


        (2)、如果想做WebAPI的JWT的鉴权和授权,必须通过 Nuget 加载的程序包,名称如下:
            Microsoft.AspNetCore.Authentication.JwtBearer
            Microsoft.IdentityModel.Tokens
        (3)、Program.cs源码如下,红色部分表示健全和授权的重要部分。

 1 using Microsoft.AspNetCore.Authentication.JwtBearer;
 2 using Microsoft.IdentityModel.Tokens;
 3 using PatrickLiu.Net6API.Extensions;
 4 using System.Text;
 5 
 6 var builder = WebApplication.CreateBuilder(args);
 7 
 8 builder.Services.AddControllers();
 9 builder.Services.AddEndpointsApiExplorer();
10 builder.Services.AddSwaggerGen();
11 
12 #region 配置鉴权
13 
14 //增加的鉴权逻辑,角色认证、策略认证都是支持的,和Net Core MVC 支持的一样。
15 JWTTokenOption tokenOption = new JWTTokenOption();
16 builder.Configuration.Bind("JWTTokenOption", tokenOption);
17 //builder.Services.Configure<JWTTokenOption>(builder.Configuration.GetSection("JWTTokenOption"));
18 builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
19     .AddJwtBearer(option =>
20 {
21     option.TokenValidationParameters = new TokenValidationParameters()
22     {
23         ValidateIssuer = true,//是否验证 Issuer(发行商)
24         ValidateAudience = true,//是否验证 Audience(受众者)
25         ValidateLifetime = true,//是否验证失效时间
26         ValidateIssuerSigningKey = true,//是否验证 Issuer 的签名键
27         ValidAudience=tokenOption.Audience,
28         ValidIssuer=tokenOption.Issuer,// ValidAudience,ValidIssuer这两项的值要和验证中心的只保持一致。
29         IssuerSigningKey=new SymmetricSecurityKey(Encoding.UTF8.GetBytes(tokenOption.SecurityKey!))         
30     };
31 });
32 
33 #endregion
34 
35 var app = builder.Build();
36 
37 app.UseSwagger();
38 app.UseSwaggerUI();
39 
40 app.UseAuthentication();
41 app.UseAuthorization();42 
43 app.MapControllers();
44 
45 app.Run();


        (4)、要实现授权的Controller增加【Authorize】特性,红色部分要注意。

 1 using Microsoft.AspNetCore.Authentication.JwtBearer;
 2 using Microsoft.AspNetCore.Authorization;
 3 using Microsoft.AspNetCore.Mvc;
 4 
 5 namespace PatrickLiu.Net6API.Resouces.Controllers
 6 {
 7     [Route("api/[controller]")]
 8     [ApiController]
 9     public class SecondController : ControllerBase
10     {
11         /// <summary>
12         /// 这里使用 JWT 进行授权检查。
13         /// </summary>
14         /// <returns></returns>
15         [HttpGet]
16         [Authorize(AuthenticationSchemes =JwtBearerDefaults.AuthenticationScheme)]
17         public object GetData()
18         {
19             return new
20             {
21                 Id = 1234,
22                 Name = "PatrickLiu"
23             };
24         }
25     }
26 }


        (5)、appsettings.json 配置文件,这里的配置要和【PatrickLiu.Net6API.AuthenticationCenter】项目配置一样,红色部分要注意。

 1 {
 2   "Logging": {
 3     "LogLevel": {
 4       "Default": "Information",
 5       "Microsoft.AspNetCore": "Warning"
 6     }
 7   },
 8   "AllowedHosts": "*",
 9   "JWTTokenOption": {
10     "Audience": "PatrickLiu.com",
11     "Issuer": "PatrickLiu.com",
12     "SecurityKey": "12333456677655ffrrffff"
13   }
14 }


    4、现在是Minimal WebAPI类型项目:
        其实,WebAPI和MinimalAPI鉴权和授权总体都是差不多,差别不大。
        (1)、我们先看一下项目截图,有一个直观感受,截图如下:
            
        (2)、如果想做WebAPI的JWT的鉴权和授权,必须通过 Nuget 加载的程序包,名称如下:
            Microsoft.AspNetCore.Authentication.JwtBearer
            Microsoft.IdentityModel.Tokens

        (3)、Program.cs 源码如下,红色标注要特别重要。

 1 using Microsoft.AspNetCore.Authentication.JwtBearer;
 2 using Microsoft.IdentityModel.Tokens;
 3 using PatrickLiu.Net6API.Extensions;
 4 using PatrickLiu.Net6API.MinimalAPI.Extension;
 5 using System.Text;
 6 
 7 var builder = WebApplication.CreateBuilder(args);
 8 
 9 builder.Services.AddEndpointsApiExplorer();
10 builder.Services.AddSwaggerGen();
11 
12 #region 1、配置鉴权逻辑
13 
14 //增加的鉴权逻辑,角色认证、策略认证都是支持的,和Net Core MVC 支持的一样。
15 JWTTokenOption tokenOption = new JWTTokenOption();
16 builder.Configuration.Bind("JWTTokenOption", tokenOption);
17 builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
18     .AddJwtBearer(option =>
19     {
20         option.TokenValidationParameters = new TokenValidationParameters()
21         {
22             ValidateIssuer = true,//是否验证 Issuer(发行商)
23             ValidateAudience = true,//是否验证 Audience(受众者)
24             ValidateLifetime = true,//是否验证失效时间
25             ValidateIssuerSigningKey = true,//是否验证 Issuer 的签名键
26             ValidAudience = tokenOption.Audience,
27             ValidIssuer = tokenOption.Issuer,// ValidAudience,ValidIssuer这两项的值要和验证中心的只保持一致。
28             IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(tokenOption.SecurityKey!))
29         };
30     });
31 
32 #endregion
33 
34 #region 2、配置授权逻辑
35 
36 //在这里不支持增加授权信息,比如:builder.Services.AddAuthorization(JwtBearerDefaults.AuthenticationScheme);,这样写是不行的,
  我们可以扩展实现 IAuthorizeData 来达到同样的目的。
37 builder.Services.AddAuthorization();
38 
39 #endregion
40 
41 var app = builder.Build();
42 
43 app.UseSwagger();
44 app.UseSwaggerUI();
45 
46 #region 3、使用鉴权授权中间件
47 
48 app.UseAuthentication();
49 app.UseAuthorization();
50 
51 #endregion
52 
53 #region 4、实现授权要求
54 
55 app.MapGet("/User", (int id, string name) =>
56 {
57     return "Hello World!";
58 }).RequireAuthorization(new CustomAuthorizeData()
59 {
60     AuthenticationSchemes = JwtBearerDefaults.AuthenticationScheme
61     //可以增加角色授权
62     //,Roles="",
63     //可以增加策略授权。
64     //Policy=""
65 });
66 
67 app.MapGet("/Products", (HttpContext context) =>
68 {
69     return new
70     {
71         Id = 123456,
72         Name = "IPhone14 Pro Max",
73         Price = 4839.23,
74         DateOfProduction = "2023/2/12 23:22"
75     };
76 });
77 
78 #endregion
79 
80 app.Run();


        (4)、扩展 IAuthorizeData 接口实现CustomAuthorizeData,可以实现对MinimalAPI授权。

 1 using Microsoft.AspNetCore.Authorization;
 2 
 3 namespace PatrickLiu.Net6API.MinimalAPI.Extension
 4 {
 5     public sealed class CustomAuthorizeData : IAuthorizeData
 6     {
 7         public string? Policy { get; set; }
 8         public string? Roles { get; set; }
 9         public string? AuthenticationSchemes { get; set; }
10     }
11 }


        (5)、appsettings.json 配置文件源码如下,红色部分是重要代码。

 1 {
 2   "Logging": {
 3     "LogLevel": {
 4       "Default": "Information",
 5       "Microsoft.AspNetCore": "Warning"
 6     }
 7   },
 8   "AllowedHosts": "*",
 9   "JWTTokenOption": {
10     "Audience": "PatrickLiu.com",
11     "Issuer": "PatrickLiu.com",
12     "SecurityKey": "12333456677655ffrrffff"
13   }
14 }


三、结束语

       好了,今天就写到这里了,现在总结一下,如果想要给WebAPI或者MinimalAPI实现授权和鉴权,总体步骤是差不多的,第一步,都要启用连个中间件,就是授权和鉴权中间件(app.UseAuthorization()、app.UseAuthentication()),然后要配置鉴权的配置逻辑,差别就在授权方面,普通WebAPI直接通过 AuthorizeAttribute 特性标注在需要授权的方法或者 Controller 类型上就可以。普通WebAPI支持所有的角色授权、策略授权等方法,并且也支持所有的Filter。MinimalAPI要实现授权,要在GetXXX方法后面调用RequireAuthorization()来实现授权的内容。不忘初心,继续努力,老天不会辜负努力的人。

与如何在 Net6.0 中对 WebAPI 进行 JWT 认证和授权相似的内容:

如何在 Net6.0 中对 WebAPI 进行 JWT 认证和授权

一、简介 我们做微服务开发,或者说做分布式开发,有一项技术我们是避不开的,那就是WebAPI,在 Net6.0中,有两类 WebAPI,一类是极简 WebAPI,它砍掉了很多冗余的东西,更纯粹的是做 API的,也更适合做微服务的开发。另外一类就是我们通常使用的正常 API,这个没得说,也是我们使用最

一套基于 .NET Core 开发的支付SDK集 - paylink

前言 在我们的日常工作开发中对接一些第三方支付是比较常见的,如最常见的就是支付宝、微信支付的对接。今天给大家推荐一个基于.NET Core开发的支付SDK集:paylink,它极大简化了API调用及通知的处理流程从而大大提供我们的工作生产效率。 运行环境 .NET Core 3.1、.NET 6.0

如何将 Autofac 整合进 Net6.0 Core MVC 项目中

一、前言 1、简而言之 Asp.Net Core Mvc,我也用了很长一段时间了,它现在的编程模型和方式还是特别棒的,都是组件开发,什么都可以替换,当然了,您别抬杠,有些还是不能替换的。自从我们进入了跨平台开发的时代,IOC容器也成了一个不可或缺的东西了。微软为我们提供了一个默认实现,那就是 ISe

如何在Net6.0里配置多版本支持并支持注释说明的Swagger

一、前言 现在已经进入了微服务的开发时代了,在这个时代,如果有人问你什么是微服务,你说不知道,就有点太丢人了,别人会有异样的眼光看你,俗话说:唾液淹死人。没办法,我们只能去学习新的东西。一提到微服务,有一个绕不过的话题就是作为微服务的载体,WebAPI是离不开的。但是我们今天不讲WebAPI是什么,

Azure DevOps(一)基于 Net6.0 的 WPF 程序如何进行持续集成、持续编译

一,引言 我们是否正在为如何快速的编译、部署客户端应用程序而烦恼?这也是博主最近遇到的问题。目前博主所在公司主要做项目级的定制化开发,多以 C/S 架构的 WPF 程序为主,每次到了协助开发团队给实施团队编译好的要测试程序包时,就会出现多人协助,编译、打包好的二进制程序包 pull 最新代码 ,以及

ASP.NET Core设置URLs的几种方法,完美解决.NET 6项目局域网IP地址远程无法访问的问题

近期在dotnet项目中遇到这样的问题:.net6 运行以后无法通过局域网IP地址远程访问。后查阅官方文档。整理出解决问题的五种方式方法,通过新建一个新的WebApi项目演示如下: 说明 操作系统:Ubuntu 22.04.2 运行时:.NET 6 开发工具:Visual Studio 2202 新

是什么让.NET7的Min和Max方法性能暴增了45倍?

简介 在之前的一篇文章.NET性能系列文章一:.NET7的性能改进中我们聊到Linq中的Min()和Max()方法.NET7比.NET6有高达45倍的性能提升,当时Benchmark代码和结果如下所示: [Params(1000)] public int Length { get; set; } p

.NET Core使用SkiaSharp快速生成二维码( 真正跨平台方案)

前言 在.NET 6之前我们一直是使用QRCoder来生成二维码(QRCoder是一个非常强大的生成二维码的组件,用到了System.Drawing.Common 包),然后从.NET 6开始,当为非 Windows 操作系统编译引用代码时,平台分析器会发出编译时警告。异常如下: System.Ty

ASP.NET 6启动时自动创建MongoDB索引

最近,在使用MongoDB时,碰到这样的一个需求:针对某个Collection手动在开发环境创建了索引,但在测试环境和生产环境不想再手动操作了,于是就想着干脆通过代码的方式在ASP.NET 6应用启动时自动创建,如果是重复创建则直接跳过。

.NET6项目连接数据库方式方法

前言 接上一篇Linux系统下创建dotnet项目,这一篇我们聊聊.NET6环境下dotnet项目连接数据库的方式方法,包括数据库字符串该如何配置。看了很多博主写的文章,连接数据库字符串配置的方式和位置五花八门,这篇文章给大家介绍一下连接数据库字符串的配置方式方法,顺便介绍下一个新创建的dotnet