ToB企服应用市场:ToB评测及商务社交产业平台

标题: ASP.NET Core 8.0 WebApi 从零开始学习JWT登录认证 [打印本页]

作者: 立聪堂德州十三局店    时间: 2024-9-8 04:18
标题: ASP.NET Core 8.0 WebApi 从零开始学习JWT登录认证
前言

我一起写后端Api我都是直接裸连的,但是现在为了规范一些,我还是打算上一个JWT功能
相关链接

   ASP.NET Web API 2系列(四):基于JWT的token身份认证方案
    Jwt-dotnet github
  Nuget选择


选好了模板,就进去看看号了,42M的下载量已经很高了,一般来说,只要超过500k的下载量,基本就是一个稳定的代码堆栈了。
进去看看内里写的怎么样

可以看到写的还是比力清晰的

知识增补

JWT不是加密算法

JWT全名 JSON Web Token。Token这部分才是加密得出来的,JWT只是一个网页认证策略。
可逆加密和不可逆加密

无论是可逆加密还是不可逆加密,都需要一个自定义的【Key】来辅助加密。可逆加密就类似于一元二次方程,key就类似于修改方程各项的系数,【Key=125】得到【x^2+2x+5】。我的原文是【1】,得到的密文就是盘算后的效果【8】。所以加密比解密要方便。
不可逆加密就是不能逆向解决的方程,比如高阶方程【x^7- x^3 +5x-3】,正向好算,逆向基本不可解。
所以现实利用的时间,可逆加密一般是解密后利用。因为可逆,所以可以用于复杂的敏感信息。
不可逆加密是判定加密后的的密文是否类似,比如暗码,是不能走漏的,所以我们的暗码只能重置,因为系统也不知道原暗码是什么。
普通Jwt(不推荐)

项目环境


Nuget



最小JWT测试

我们先不管JWT是怎样添加到ASP.NET Core内里的,我们先测试JWT的加密和登录验证的功能。
  1. /// <summary>
  2. /// 加密密钥
  3. /// </summary>
  4. private static readonly string jwtKey = "TokenKey";
  5. public record UserTest(string Name,string Account,string Password);
  6. static void Main(string[] args)
  7. {
  8.     UserTest userTest = new UserTest("小王","admin","1dixa0d");
  9.     Console.WriteLine("原文");
  10.     Console.WriteLine(JsonConvert.SerializeObject(userTest));//{"Name":"小王","Account":"admin","Password":"1dixa0d"}
  11.     var encoder = GetEncoder();
  12.     string jwtToken = encoder.Encode(userTest,jwtKey);
  13.     Console.WriteLine("加密");
  14.     Console.WriteLine(jwtToken);//eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJOYW1lIjoi5bCP546LIiwiQWNjb3VudCI6ImFkbWluIiwiUGFzc3dvcmQiOiIxZGl4YTBkIn0.C_tlDhHpkjAkJpRRdnqz6Jn2FmP0qONAI4oNl8Ye9wM
  15.     var decoder =  GetDecoder();
  16.     var decodeData =  decoder.Decode(jwtToken,jwtKey);
  17.     Console.WriteLine("解密");
  18.     Console.WriteLine(decodeData);//{"Name":"小王","Account":"admin","Password":"1dixa0d"}
  19.     Console.WriteLine("Hello, World!");
  20. }
  21. /// <summary>
  22. /// 获取加密解密
  23. /// </summary>
  24. /// <returns></returns>
  25. public static IJwtEncoder GetEncoder()
  26. {
  27.     IJwtAlgorithm algorithm = new HMACSHA256Algorithm();//加密方式
  28.     IJsonSerializer serializer = new JsonNetSerializer();//序列化Json
  29.     IBase64UrlEncoder urlEncoder = new JwtBase64UrlEncoder();//base64加解密
  30.     IJwtEncoder encoder = new JwtEncoder(algorithm, serializer, urlEncoder);//JWT编码
  31.     return encoder;
  32. }
  33. /// <summary>
  34. /// 获取解密密钥
  35. /// </summary>
  36. /// <returns></returns>
  37. public static IJwtDecoder GetDecoder()
  38. {
  39.     IJsonSerializer serializer = new JsonNetSerializer();
  40.     IDateTimeProvider provider = new UtcDateTimeProvider();
  41.     IJwtValidator validator = new JwtValidator(serializer, provider);
  42.     IBase64UrlEncoder urlEncoder = new JwtBase64UrlEncoder();
  43.     IJwtAlgorithm algorithm = new HMACSHA256Algorithm();
  44.     IJwtDecoder decoder = new JwtDecoder(serializer, validator, urlEncoder, algorithm);
  45.     return decoder;
  46. }
复制代码

这里的JWT的加密解密算法是可以自己搭配的,选择加密算法,这里我就不展开了。具体可以看官方文档

在WebApi中简单利用

起首我们之前用到了可逆的加密息争密。那我们就需要用一个判定是否逾期的类
  1. public class UserJwtLogin
  2. {
  3.     /// <summary>
  4.     /// 用户Id,因为数据库的Id是唯一的,不会重复
  5.     /// </summary>
  6.     public long UserId { get; set; }   
  7.     /// <summary>
  8.     /// 过期时间
  9.     /// </summary>
  10.     public DateTime ExpireTime { get; set; }
  11. }
复制代码
具体的解决方案就在这个文章内里了,我就不照抄了,拾人牙慧。
   ASP.NET Web API 2系列(四):基于JWT的token身份认证方案
  我这里是这么写的
新建一个JwtHelper
  1. public static class JwtHelper
  2. {
  3.     private static readonly string JwtKey = "这里填你的密钥";
  4.     /// <summary>
  5.     /// 获取加密解密
  6.     /// </summary>
  7.     /// <returns></returns>
  8.     private static IJwtEncoder GetEncoder()
  9.     {
  10.         IJwtAlgorithm algorithm = new HMACSHA256Algorithm();//加密方式
  11.         IJsonSerializer serializer = new JsonNetSerializer();//序列化Json
  12.         IBase64UrlEncoder urlEncoder = new JwtBase64UrlEncoder();//base64加解密
  13.         IJwtEncoder encoder = new JwtEncoder(algorithm, serializer, urlEncoder);//JWT编码
  14.         return encoder;
  15.     }
  16.     /// <summary>
  17.     /// 获取解密密钥
  18.     /// </summary>
  19.     /// <returns></returns>
  20.     private static IJwtDecoder GetDecoder()
  21.     {
  22.         IJsonSerializer serializer = new JsonNetSerializer();
  23.         IDateTimeProvider provider = new UtcDateTimeProvider();
  24.         IJwtValidator validator = new JwtValidator(serializer, provider);
  25.         IBase64UrlEncoder urlEncoder = new JwtBase64UrlEncoder();
  26.         IJwtAlgorithm algorithm = new HMACSHA256Algorithm();
  27.         IJwtDecoder decoder = new JwtDecoder(serializer, validator, urlEncoder, algorithm);
  28.         return decoder;
  29.     }
  30.     /// <summary>
  31.     /// 加密
  32.     /// </summary>
  33.     public static string Encode(object payload)
  34.     {
  35.         var encoder = GetEncoder();
  36.         var token = encoder.Encode(payload, JwtKey);
  37.         return token;
  38.     }
  39.     /// <summary>
  40.     /// 解密
  41.     /// </summary>
  42.     public static T Decode<T>(string token)
  43.     {
  44.         var decoder = GetDecoder();
  45.         var data =  decoder.Decode(token,JwtKey);
  46.         var res  = JsonConvert.DeserializeObject<T>(data);
  47.         return res;
  48.     }
  49.     /// <summary>
  50.     /// 解密,只返回Json文本
  51.     /// </summary>
  52.     /// <param name="token"></param>
  53.     /// <returns></returns>
  54.     public static string Decode(string token)
  55.     {
  56.         var decoder = GetDecoder();
  57.         var data = decoder.Decode(token, JwtKey);
  58.         return data;
  59.     }
  60. }
复制代码
两个实体类
  1.    public class UserJwtLogin
  2.    {
  3.        /// <summary>
  4.        /// 用户Id,因为数据库的Id是唯一的,不会重复
  5.        /// </summary>
  6.        public long UserId { get; set; }   
  7.        /// <summary>
  8.        /// 过期时间
  9.        /// </summary>
  10.        public DateTime ExpireTime { get; set; }
  11.    }
复制代码
  1. public class WebMsg
  2. {
  3.     public int Code { get; set; } = 200;
  4.     public bool Success { get; set; } = true;
  5.     public object Data {get; set; }
  6.     public string Msg { get; set; } = "操作成功!";
  7.     public WebMsg()
  8.     {
  9.     }
  10.     public WebMsg(object data)
  11.     {
  12.         Data = data;
  13.     }
  14. }
复制代码
简单利用

  1. /// <summary>
  2. /// Jwt登录
  3. /// </summary>
  4. [Route("api/[controller]/[action]")]
  5. [ApiController]
  6. public class LoginController : ControllerBase
  7. {
  8.         //这个是我的Nlog配置,这里不做展开
  9.     private NlogService nlogService;
  10.     public LoginController(NlogService nlogService)
  11.     {
  12.         this.nlogService = nlogService;
  13.     }
  14.     /// <summary>
  15.     /// JWT登录
  16.     /// </summary>
  17.     /// <param name="username">账号</param>
  18.     /// <param name="password">密码</param>
  19.     /// <returns></returns>
  20.     [HttpGet]
  21.     public WebMsg Login(string username, string password)
  22.     {
  23.         if (username == null || password == null)
  24.         {
  25.             return new WebMsg()
  26.             {
  27.                 Msg = "登录信息为空",
  28.                 Success = false,
  29.             };
  30.         }
  31.         if (username == "admin" && password == "123456")
  32.         {
  33.                         //这里是模拟拿到数据库的User表的Id
  34.             var pyload = new UserJwtLogin()
  35.             {
  36.                 UserId = 291,
  37.                 ExpireTime = DateTime.Now.AddDays(1)
  38.             };
  39.             var token = JwtHelper.Encode(pyload);
  40.             return new WebMsg(token);
  41.         }
  42.         else
  43.         {
  44.             return new WebMsg()
  45.             {
  46.                 Msg = "登录失败,账号或者密码错误",
  47.                 Success = false,
  48.             };
  49.         }
  50.     }
  51.     /// <summary>
  52.     /// Jwt解密
  53.     /// </summary>
  54.     /// <param name="token"></param>
  55.     /// <returns></returns>
  56.     [HttpGet]
  57.     public WebMsg Decode(string token)
  58.     {
  59.         try
  60.         {
  61.             var res = JwtHelper.Decode(token);
  62.             return new WebMsg(res);
  63.         }
  64.         catch (Exception ex)
  65.         {
  66.             nlogService.Error("登录解析失败:" + token);
  67.             nlogService.Error(ex.Message);
  68.             return new WebMsg() {
  69.                 Msg = "登录解析失败:" + token,
  70.                 Success = false,
  71.             };
  72.         }
  73.     }
  74. }
复制代码
运行效果


  1. {
  2.   "code": 200,
  3.   "success": true,
  4.   "data": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJVc2VySWQiOjI5MSwiRXhwaXJlVGltZSI6IjIwMjQtMDMtMTRUMTM6MjE6MzYuNjE3NDk0KzA4OjAwIn0.sxh9sM4gQoCfFfim-MQSsHqDQX3Dji3FZaEu4t06D1s",
  5.   "msg": "操作成功!"
  6. }
复制代码

  1. {
  2.   "code": 200,
  3.   "success": true,
  4.   "data": "{"UserId":291,"ExpireTime":"2024-03-14T13:21:36.617494+08:00"}",
  5.   "msg": "操作成功!"
  6. }
复制代码
WebApi 授权,博客太老了,尝试失败

这里我们就用简单的授权,复杂的授权可以自己去看微软官方文档
   ASP.NET Core 中的简单授权
  

然后我发现.net core 8.0的认证方式好像变了,我按照博客的写法发现不让我重写了

这个方法是.net framework上面用的,.net core 用不了。我想还是算了,用.net core 的方法好了



WebApi .net core 8.0 最新版Jwt (微软官方集成)

我看了一天的博客,终于解决了JWT认证的题目。
   在没有 ASP.NET CoreIdentity的情况下利用cookie身份验证
    ASP.NET Core 6.0 添加 JWT 认证和授权
    .Net Core WebApi集成JWT实现身份认证
  

重新新建一个Webapi

这里我就不多说了
   .NET Core webapi 从零开始在IIS上面发布后端接口
  我们还是要改一下的,因为之前的我测试的时间,发现Builder内里的代码实在是太多了,这里我们分开一下
  1. using Microsoft.OpenApi.Models;
  2. using System.Reflection;
  3. namespace JtwTestWebApi
  4. {
  5.     public class Program
  6.     {
  7.         public static void Main(string[] args)
  8.         {
  9.             var builder = WebApplication.CreateBuilder(args);
  10.             var MyPolicy = "MyPolicy";
  11.             // Add services to the container.
  12.             builder.Services.AddControllers();
  13.             // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle
  14.             builder.Services.AddEndpointsApiExplorer();
  15.             builder.Services.AddSwaggerGen();
  16.             //为了防止配套太多,代码混乱。这里自定义了一个方法
  17.             AddMyService(builder);
  18.             var app = builder.Build();
  19.             // Configure the HTTP request pipeline.
  20.             if (app.Environment.IsDevelopment())
  21.             {
  22.                
  23.             }
  24.             app.UseSwagger();
  25.             app.UseSwaggerUI();
  26.             app.UseStatusCodePagesWithRedirects("/swagger/index.html");
  27.             app.UseHttpsRedirection();
  28.             app.UseAuthorization();
  29.             app.MapControllers();
  30.             app.Run();
  31.         }
  32.         /// <summary>
  33.         /// 为了防止代码过于臃肿,将新的配置放在这里写
  34.         /// </summary>
  35.         /// <param name="builder"></param>
  36.         public static void AddMyService(WebApplicationBuilder builder)
  37.         {
  38.             builder.Services.AddCors(options =>
  39.             {
  40.                 options.AddPolicy("MyPolicy", policy =>
  41.                 {
  42.                     policy.AllowAnyHeader().AllowAnyOrigin().AllowAnyMethod();
  43.                 });
  44.             });
  45.             builder.Services.AddSwaggerGen(options =>
  46.             {
  47.                 options.SwaggerDoc("v1", new OpenApiInfo
  48.                 {
  49.                     Version = "v1",
  50.                     Title = "API标题",
  51.                     Description = $"API描述,v1版本"
  52.                 });
  53.                 var xmlFilename = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml";
  54.                 //IncludeXmlComments 第二参数 true 则显示 控制器 注释
  55.                 options.IncludeXmlComments(Path.Combine(AppContext.BaseDirectory, xmlFilename), true);
  56.             });
  57.         }
  58.     }
  59. }
复制代码
简单Controller

  1. public class WebMsg
  2. {
  3.     public object Data { get; set; }
  4.     public bool Success { get; set; } = true;
  5.     public string Msg { get; set; } = "操作成功!";
  6.     public WebMsg()
  7.     {
  8.     }
  9.     public WebMsg(object data)
  10.     {
  11.         Data = data;
  12.     }
  13. }
复制代码
  1. /// <summary>
  2. /// 测试控制器
  3. /// </summary>
  4. [Route("api/[controller]/[action]")]
  5. [ApiController]
  6. public class TestController : ControllerBase
  7. {
  8.     /// <summary>
  9.     /// 测试返回值
  10.     /// </summary>
  11.     /// <returns></returns>
  12.     [HttpGet]
  13.     public WebMsg GetTest()
  14.     {
  15.         return new WebMsg("测试返回值");
  16.     }
  17. }
复制代码

最简单的Jwt认证

我们知道Jwt其实就是生成和验证两个功能。微软把这个功能集成到一个JwtBearer库内里了。

为了方便Json打印,添加个Newtonsoft

获取JwtConfig

我们在appsetting.json内里添加
  1.   "JwtConfig": {
  2.     "SecretKey": "123123123123", // 密钥   可以是guid 也可以是随便一个字符串
  3.     "Issuer": "XiaoWang", // 颁发者
  4.     "Audience": "XiaoWang", // 接收者
  5.     "Expired": 30 // 过期时间(30min)
  6.   }
复制代码

  1. public class JwtConfig
  2. {
  3.      /// <summary>
  4.      /// 密钥
  5.      /// </summary>
  6.      public string SecretKey { get; set; }   
  7.      /// <summary>
  8.      /// 发布者
  9.      /// </summary>
  10.      public string Issuer { get; set; }
  11.      /// <summary>
  12.      /// 接受者
  13.      /// </summary>
  14.      public string Audience { get; set; }
  15.      /// <summary>
  16.      /// 过期时间(min)
  17.      /// </summary>
  18.      public int Expired { get; set; }
  19. }
复制代码
获取Config
  1. var jwtConfig = new JwtConfig();
  2. builder.Configuration.Bind("JwtConfig",jwtConfig);
复制代码


新建JwtHelper类

  1. public class JwtHelper
  2. {
  3.      public JwtConfig JwtConfig { get; set; }
  4.      public JwtHelper()
  5.      {
  6.      }
  7.      /// <summary>
  8.      /// 添加Jwt服务
  9.      /// </summary>
  10.      public void AddJwtService()
  11.      {
  12.      }
  13.      /// <summary>
  14.      /// 返回
  15.      /// </summary>
  16.      /// <returns></returns>
  17.      public string GetJwtToken()
  18.      {
  19.          //简单测试一下
  20.          var token = JsonConvert.SerializeObject(JwtConfig);
  21.          return token;
  22.      }
  23. }
复制代码
我们应该利用Ioc的方式注入JwtHelper
  1. var jwtConfig = new JwtConfig();
  2. builder.Configuration.Bind("JwtConfig",jwtConfig);
  3. var jwtHelper = new JwtHelper() {    JwtConfig = jwtConfig};//将JwtHelper添加到Services内里builder.Services.AddSingleton<JwtHelper>(jwtHelper);
复制代码

然后在控制器内里获取Token
  1. /// <summary>
  2. /// 测试控制器
  3. /// </summary>
  4. [Route("api/[controller]/[action]")]
  5. [ApiController]
  6. public class TestController : ControllerBase
  7. {
  8.     private JwtHelper jwtHelper;
  9.     /// <summary>
  10.     /// 通过Ioc得到Jwt
  11.     /// </summary>
  12.     /// <param name="jwtHelper"></param>
  13.     public TestController(JwtHelper jwtHelper) {
  14.         this.jwtHelper = jwtHelper;
  15.     }
  16.     /// <summary>
  17.     /// 测试返回值
  18.     /// </summary>
  19.     /// <returns></returns>
  20.     [HttpGet]
  21.     public WebMsg GetTest()
  22.     {
  23.         return new WebMsg("测试返回值");
  24.     }
  25.     /// <summary>
  26.     /// 获取JwtToken
  27.     /// </summary>
  28.     /// <returns></returns>
  29.     [HttpGet]
  30.     public WebMsg GetJwtToken()
  31.     {
  32.         var token = jwtHelper.GetJwtToken();
  33.         return new WebMsg(token);
  34.     }
  35. }
复制代码

接下来我们修改一下GetJwtToken这个函数即可
完善JwtConfig

  1. using Microsoft.IdentityModel.Tokens;
  2. using System.Text;
  3. namespace JtwTestWebApi.Models
  4. {
  5.     public class JwtConfig
  6.     {
  7.         /// <summary>
  8.         /// 密钥
  9.         /// </summary>
  10.         public string SecretKey { get; set; }
  11.         /// <summary>
  12.         /// 发布者
  13.         /// </summary>
  14.         public string Issuer { get; set; }
  15.         /// <summary>
  16.         /// 接受者
  17.         /// </summary>
  18.         public string Audience { get; set; }
  19.         /// <summary>
  20.         /// 过期时间(min)
  21.         /// </summary>
  22.         public int Expired { get; set; }
  23.         /// <summary>
  24.         /// 生效时间
  25.         /// </summary>
  26.         public DateTime NotBefore => DateTime.Now;
  27.         /// <summary>
  28.         /// 过期时间
  29.         /// </summary>
  30.         public DateTime Expiration => DateTime.Now.AddMinutes(Expired);
  31.         /// <summary>
  32.         /// 密钥Bytes
  33.         /// </summary>
  34.         private SecurityKey SigningKey => new SymmetricSecurityKey(Encoding.UTF8.GetBytes(SecretKey));
  35.         /// <summary>
  36.         /// 加密后的密钥,使用HmacSha256加密
  37.         /// </summary>
  38.         public SigningCredentials SigningCredentials =>
  39.             new SigningCredentials(SigningKey, SecurityAlgorithms.HmacSha256);
  40.     }
  41. }
复制代码
在JwtHelper内里利用
  1. /// <summary>
  2. /// 最简单的JwtToken
  3. /// </summary>
  4. /// <returns></returns>
  5. public string GetJwtToken()
  6. {
  7.     var claims = new List<Claim>();
  8.     var jwtSecurityToken = new JwtSecurityToken(
  9.             JwtConfig.Issuer,
  10.             JwtConfig.Audience,
  11.             claims,
  12.             JwtConfig.NotBefore,
  13.             JwtConfig.Expiration,
  14.             JwtConfig.SigningCredentials
  15.         );
  16.     var token = new JwtSecurityTokenHandler().WriteToken( jwtSecurityToken );
  17.     return token;
  18. }
  19.       
复制代码
运行报错,说明密钥的长度太短了,我们加长一下


返回乐成!

  1. eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJuYmYiOjE3MTAzODUyODgsImV4cCI6MTcxMDM4NzA4OCwiaXNzIjoiWGlhb1dhbmciLCJhdWQiOiJYaWFvV2FuZyJ9.v7UbQOba7VoNgoiRsoIQkFJKQTFBMLJlYEKBIfdFV4o
复制代码
授权

加密了,肯定要有对应的授权
在JwtConfig内里添加对应的授权
  1. public class JwtConfig
  2. {
  3.     /// <summary>
  4.     /// 密钥
  5.     /// </summary>
  6.     public string SecretKey { get; set; }
  7.     /// <summary>
  8.     /// 发布者
  9.     /// </summary>
  10.     public string Issuer { get; set; }
  11.     /// <summary>
  12.     /// 接受者
  13.     /// </summary>
  14.     public string Audience { get; set; }
  15.     /// <summary>
  16.     /// 过期时间(min)
  17.     /// </summary>
  18.     public int Expired { get; set; }
  19.     /// <summary>
  20.     /// 生效时间
  21.     /// </summary>
  22.     public DateTime NotBefore => DateTime.Now;
  23.     /// <summary>
  24.     /// 过期时间
  25.     /// </summary>
  26.     public DateTime Expiration => DateTime.Now.AddMinutes(Expired);
  27.     /// <summary>
  28.     /// 密钥Bytes
  29.     /// </summary>
  30.     private SecurityKey SigningKey => new SymmetricSecurityKey(Encoding.UTF8.GetBytes(SecretKey));
  31.     /// <summary>
  32.     /// 加密后的密钥,使用HmacSha256加密
  33.     /// </summary>
  34.     public SigningCredentials SigningCredentials =>
  35.         new SigningCredentials(SigningKey, SecurityAlgorithms.HmacSha256);
  36.     /// <summary>
  37.     /// 认证用的密钥
  38.     /// </summary>
  39.     public SymmetricSecurityKey SymmetricSecurityKey => new SymmetricSecurityKey(Encoding.UTF8.GetBytes(SecretKey));
  40. }
复制代码

在JwtHelper中
  1. /// <summary>
  2. /// 添加Jwt服务
  3. /// </summary>
  4. public void AddJwtService(IServiceCollection services)
  5. {
  6.     services.AddAuthentication(option =>
  7.     {
  8.         //认证middleware配置
  9.         option.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
  10.         option.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
  11.     })
  12.     .AddJwtBearer(options =>
  13.     {
  14.         options.TokenValidationParameters = new TokenValidationParameters
  15.         {
  16.             //Token颁发机构
  17.             ValidIssuer = JwtConfig.Issuer,
  18.             //颁发给谁
  19.             ValidAudience = JwtConfig.Audience,
  20.             //这里的key要进行加密
  21.             IssuerSigningKey = JwtConfig.SymmetricSecurityKey,
  22.             //是否验证Token有效期,使用当前时间与Token的Claims中的NotBefore和Expires对比
  23.             ValidateLifetime = true,
  24.         };
  25.     });
  26. }
复制代码
调用JwtHelper
  1.   var jwtConfig = new JwtConfig();
  2.   builder.Configuration.Bind("JwtConfig",jwtConfig);
  3.   var jwtHelper = new JwtHelper() {
  4.       JwtConfig = jwtConfig
  5.   };
  6.   //将JwtHelper添加到Services里面
  7.   builder.Services.AddSingleton<JwtHelper>(jwtHelper);
  8.   jwtHelper.AddJwtService(builder.Services);
复制代码
在app中启用
  1.             app.UseHttpsRedirection();
  2.             app.UseAuthentication();//要在授权之前认证,这个和[Authorize]特性有关
  3.             app.UseAuthorization();
复制代码
一定要在za之前利用ca

授权测试

我们接口最好单独开一个获取Token的接口
TestController
  1. using JtwTestWebApi.Models;
  2. using JtwTestWebApi.Utils;
  3. using Microsoft.AspNetCore.Authorization;
  4. using Microsoft.AspNetCore.Http;
  5. using Microsoft.AspNetCore.Mvc;
  6. namespace JtwTestWebApi.Controllers
  7. {
  8.     /// <summary>
  9.     /// 测试控制器
  10.     /// </summary>
  11.     [Route("api/[controller]/[action]")]
  12.     [ApiController]
  13.     public class TestController : ControllerBase
  14.     {
  15.         private JwtHelper jwtHelper;
  16.         /// <summary>
  17.         /// 通过Ioc得到Jwt
  18.         /// </summary>
  19.         /// <param name="jwtHelper"></param>
  20.         public TestController(JwtHelper jwtHelper) {
  21.             this.jwtHelper = jwtHelper;
  22.         }
  23.         /// <summary>
  24.         /// 测试返回值
  25.         /// </summary>
  26.         /// <returns></returns>
  27.         [HttpGet]
  28.         public WebMsg GetTest()
  29.         {
  30.             return new WebMsg("测试返回值");
  31.         }
  32.         /// <summary>
  33.         /// 获取JwtToken
  34.         /// </summary>
  35.         /// <returns></returns>
  36.         [HttpGet]
  37.         public WebMsg GetJwtToken()
  38.         {
  39.             var token = jwtHelper.GetJwtToken();
  40.             return new WebMsg(token);
  41.         }
  42.         /// <summary>
  43.         /// 可以在方法前面加Authorize
  44.         /// </summary>
  45.         /// <returns></returns>
  46.         [Authorize]
  47.         [HttpGet]
  48.         public WebMsg GetByJwt()
  49.         {
  50.             return new WebMsg("Jwt测试成功!");
  51.         }
  52.     }
  53. }
复制代码
JtwTestWebApi
如果我们在类前面添加了[Authorize],下面全部的接口都有Jwt认证。想放开Jtw认证,利用[AllowAnonymous]标记方法即可
  1. using JtwTestWebApi.Models;
  2. using Microsoft.AspNetCore.Authorization;
  3. using Microsoft.AspNetCore.Http;
  4. using Microsoft.AspNetCore.Mvc;
  5. namespace JtwTestWebApi.Controllers
  6. {
  7.     /// <summary>
  8.     /// Jwt测试类
  9.     /// </summary>
  10.     [Route("api/[controller]/[action]")]
  11.     [ApiController]
  12.     [Authorize]
  13.     public class JwtTestController : ControllerBase
  14.     {
  15.         /// <summary>
  16.         /// 不需要Jwt
  17.         /// </summary>
  18.         /// <returns></returns>
  19.         [AllowAnonymous]
  20.         [HttpGet]
  21.         public WebMsg NoJwtGet()
  22.         {
  23.             return new WebMsg("我不需要Jwt");
  24.         }
  25.         /// <summary>
  26.         /// 需要Jwt
  27.         /// </summary>
  28.         /// <returns></returns>
  29.         [HttpGet]
  30.         public WebMsg JwtGet()
  31.         {
  32.             return new WebMsg("我需要Jwt");
  33.         }
  34.     }
  35. }
复制代码
认证失败的效果

能通过Jwt的请求

既然我们拦截了请求,我们也得对符合规范的请求放行。那什么样的请求能放行呢?在Header中的【Authorization】中添加【Bearer {token}】才气放行。
PostMan测试



测试乐成!

逾期测试

   .NetCore JWT token逾期时间设置
  Jwt的逾期是由两个数据综合相加的。一个是生成Token的逾期时间

一个是缓冲时间,默认5分钟。因为服务器的时间大概不同步。

所以总逾期时间=逾期时间+缓冲时间

为了更简单的获取Token,我们直接把返回的Token自带[Bearer ]这个前缀好了
Swagger 全局Header

在JwtHelper中添加全局静态方法
  1. /// <summary>
  2. /// Swagger添加Jwt功能
  3. /// </summary>
  4. /// <param name="options"></param>
  5. public static void SwaggerAddJwtHeader(SwaggerGenOptions options)
  6. {
  7.     options.AddSecurityRequirement(new OpenApiSecurityRequirement()
  8.         {
  9.             {
  10.                 new OpenApiSecurityScheme
  11.                 {
  12.                     Reference = new OpenApiReference {
  13.                         Type = ReferenceType.SecurityScheme,
  14.                         Id = "Bearer",
  15.                     }
  16.                 },
  17.             new string[] { }
  18.             }
  19.         });
  20.     options.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
  21.     {
  22.         Description = "JWT授权(数据将在请求头中进行传输) 在下方输入Bearer {token} 即可,注意两者之间有空格",
  23.         Name = "Authorization",//jwt默认的参数名称
  24.         In = ParameterLocation.Header,//jwt默认存放Authorization信息的位置(请求头中)
  25.         Type = SecuritySchemeType.ApiKey,
  26.         BearerFormat = "JWT",
  27.         Scheme = "Bearer"
  28.     });
  29. }
复制代码





获取Jwt中的信息

因为我们的Jwt是自带【Bearer 】这个请求头的,所以去掉前面的头,内里其实是可以解密的
  1. /// <summary>
  2. /// 获取Jwt的信息
  3. /// </summary>
  4. /// <param name="request"></param>
  5. /// <returns></returns>
  6. public IEnumerable<Claim> Decode(HttpRequest request)
  7. {
  8.      
  9.      var authorization = request.Headers["Authorization"].ToString();
  10.      //因为我们的Jwt是自带【Bearer 】这个请求头的,所以去掉前面的头
  11.      var auth = authorization.Split(" ")[1];
  12.      var handler = new JwtSecurityTokenHandler();
  13.      //反解密,获取其中的Claims
  14.      var payload = handler.ReadJwtToken(auth).Payload;
  15.      var claims = payload.Claims;
  16.      return claims;
  17. }
复制代码
解密能拿到是因为我们加密的时间就已经放进去了
  1. /// <summary>
  2. /// 添加claims信息
  3. /// </summary>
  4. /// <param name="claims"></param>
  5. /// <returns></returns>
  6. public string GetJwtToken(List<Claim> claims)
  7. {
  8.      var jwtSecurityToken = new JwtSecurityToken(
  9.              JwtConfig.Issuer,
  10.              JwtConfig.Audience,
  11.              claims,
  12.              JwtConfig.NotBefore,
  13.              JwtConfig.Expiration,
  14.              JwtConfig.SigningCredentials
  15.          );
  16.      var token = new JwtSecurityTokenHandler().WriteToken(jwtSecurityToken);
  17.      token = "Bearer " + token;
  18.      return token;
  19. }
复制代码
  1. /// <summary>
  2. /// 获取JwtToken
  3. /// </summary>
  4. /// <returns></returns>
  5. [HttpGet]
  6. public WebMsg GetJwtToken2()
  7. {
  8.         //我们加密的时候,就放进去了一些额外的信息
  9.      var token = jwtHelper.GetJwtToken(new List<Claim>()
  10.      {
  11.          new Claim("UserId","2"),
  12.          new Claim("UserName","3")
  13.      });
  14.      return new WebMsg(token);
  15. }
复制代码
  1. /// <summary>
  2. /// 可以在方法前面加Authorize
  3. /// </summary>
  4. /// <returns></returns>
  5. [Authorize]
  6. [HttpGet]
  7. public WebMsg GetByJwt()
  8. {
  9.         //获取解密后的Claim
  10.     var dic = jwtHelper.Decode(this.Request);
  11.     return new WebMsg("Jwt测试成功!");
  12. }
复制代码

这样我们就可以把一些比力隐私的数据放在内里,比如用户Id,这样防止走漏。
简单封装一下

  1. using JtwTestWebApi.Models;
  2. using Microsoft.AspNetCore.Authentication.JwtBearer;
  3. using Microsoft.IdentityModel.Tokens;
  4. using Microsoft.OpenApi.Models;
  5. using Newtonsoft.Json;
  6. using Swashbuckle.AspNetCore.SwaggerGen;
  7. using System.IdentityModel.Tokens.Jwt;
  8. using System.Security.Claims;
  9. using System.Text;
  10. namespace JtwTestWebApi.Utils
  11. {
  12.     public class JwtHelper
  13.     {
  14.         public JwtConfig JwtConfig { get; set; }
  15.         public JwtHelper()
  16.         {
  17.         }
  18.         /// <summary>
  19.         /// 添加Jwt服务
  20.         /// </summary>
  21.         public void AddJwtService(IServiceCollection services)
  22.         {
  23.             services.AddAuthentication(option =>
  24.             {
  25.                 //认证middleware配置
  26.                 option.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
  27.                 option.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
  28.             })
  29.             .AddJwtBearer(options =>
  30.             {
  31.                 options.TokenValidationParameters = new TokenValidationParameters
  32.                 {
  33.                     //Token颁发机构
  34.                     ValidIssuer = JwtConfig.Issuer,
  35.                     //颁发给谁
  36.                     ValidAudience = JwtConfig.Audience,
  37.                     //这里的key要进行加密
  38.                     IssuerSigningKey = JwtConfig.SymmetricSecurityKey,
  39.                     //是否验证Token有效期,使用当前时间与Token的Claims中的NotBefore和Expires对比
  40.                     ValidateLifetime = true,
  41.                     ValidateIssuer = true,
  42.                     ValidateAudience = true,
  43.                     ValidateIssuerSigningKey = true,
  44.                     RequireExpirationTime = true,
  45.                 };
  46.             });
  47.         }
  48.         /// <summary>
  49.         /// 最简单的JwtToken
  50.         /// </summary>
  51.         /// <returns></returns>
  52.         public string GetJwtToken()
  53.         {
  54.             var claims = new List<Claim>();
  55.             var jwtSecurityToken = new JwtSecurityToken(
  56.                     JwtConfig.Issuer,
  57.                     JwtConfig.Audience,
  58.                     claims,
  59.                     JwtConfig.NotBefore,
  60.                     JwtConfig.Expiration,
  61.                     JwtConfig.SigningCredentials
  62.                 );
  63.             var token = new JwtSecurityTokenHandler().WriteToken(jwtSecurityToken);
  64.             token = "Bearer " + token;
  65.             return token;
  66.         }
  67.         /// <summary>
  68.         /// 添加claims信息
  69.         /// </summary>
  70.         /// <param name="claims"></param>
  71.         /// <returns></returns>
  72.         public string GetJwtToken(List<Claim> claims)
  73.         {
  74.             var jwtSecurityToken = new JwtSecurityToken(
  75.                     JwtConfig.Issuer,
  76.                     JwtConfig.Audience,
  77.                     claims,
  78.                     JwtConfig.NotBefore,
  79.                     JwtConfig.Expiration,
  80.                     JwtConfig.SigningCredentials
  81.                 );
  82.             var token = new JwtSecurityTokenHandler().WriteToken(jwtSecurityToken);
  83.             token = "Bearer " + token;
  84.             return token;
  85.         }
  86.         /// <summary>
  87.         /// UserModel类Token
  88.         /// </summary>
  89.         /// <param name="user"></param>
  90.         /// <returns></returns>
  91.         public string GetJwtToken(JwtUserModel user)
  92.         {
  93.             var claims = new List<Claim>() {
  94.                 new Claim("UserId",user.UserId.ToString()),
  95.                 new Claim("UserName",user.UserName),
  96.                 new Claim("UserType",user.UserType.ToString()),
  97.             };
  98.             return GetJwtToken(claims);
  99.         }
  100.         /// <summary>
  101.         /// Swagger添加Jwt功能
  102.         /// </summary>
  103.         /// <param name="options"></param>
  104.         public static void SwaggerAddJwtHeader(SwaggerGenOptions options)
  105.         {
  106.             options.AddSecurityRequirement(new OpenApiSecurityRequirement()
  107.                 {
  108.                     {
  109.                         new OpenApiSecurityScheme
  110.                         {
  111.                             Reference = new OpenApiReference {
  112.                                 Type = ReferenceType.SecurityScheme,
  113.                                 Id = "Bearer",
  114.                             }
  115.                         },
  116.                     new string[] { }
  117.                     }
  118.                 });
  119.             options.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
  120.             {
  121.                 Description = "JWT授权(数据将在请求头中进行传输) 在下方输入Bearer {token} 即可,注意两者之间有空格",
  122.                 Name = "Authorization",//jwt默认的参数名称
  123.                 In = ParameterLocation.Header,//jwt默认存放Authorization信息的位置(请求头中)
  124.                 Type = SecuritySchemeType.ApiKey,
  125.                 BearerFormat = "JWT",
  126.                 Scheme = "Bearer"
  127.             });
  128.         }
  129.         /// <summary>
  130.         /// 获取Jwt的信息
  131.         /// </summary>
  132.         /// <param name="request"></param>
  133.         /// <returns></returns>
  134.         public IEnumerable<Claim> Decode(HttpRequest request)
  135.         {
  136.             var authorization = request.Headers["Authorization"].ToString();
  137.             //因为我们的Jwt是自带【Bearer 】这个请求头的,所以去掉前面的头
  138.             var auth = authorization.Split(" ")[1];
  139.             var handler = new JwtSecurityTokenHandler();
  140.             //反解密,获取其中的Claims
  141.             var payload = handler.ReadJwtToken(auth).Payload;
  142.             var claims = payload.Claims;
  143.             return claims;
  144.         }
  145.         /// <summary>
  146.         /// 解析得到User
  147.         /// </summary>
  148.         /// <param name="request"></param>
  149.         /// <returns></returns>
  150.         public JwtUserModel DecodeToUser(HttpRequest request)
  151.         {
  152.             var claims = Decode(request);
  153.             var user = new JwtUserModel()
  154.             {
  155.                 UserId = claims.Where(t => t.Type == "UserId").First().Value,
  156.                 UserName = claims.Where(t => t.Type == "UserName").First().Value,
  157.                 UserType = claims.Where(t => t.Type == "UserType").First().Value
  158.             };
  159.             return user;
  160.         }
  161.     }
  162. }
复制代码
  1. [HttpGet]
  2. public WebMsg GetJwtToken3()
  3. {
  4.     var token = jwtHelper.GetJwtToken(new JwtUserModel()
  5.     {
  6.         UserName = "小王",
  7.         UserId = "32",
  8.         UserType = "admin"
  9.     });
  10.     return new WebMsg(token);
  11. }
  12. [Authorize]
  13. [HttpGet]
  14. public WebMsg GetByJwt3()
  15. {
  16.     var dic = jwtHelper.DecodeToUser(this.Request);
  17.     return new WebMsg("Jwt测试成功!");
  18. }
复制代码
运行得到效果

Jwt授权模式底子讲解

介绍三种授权方式(Policy、Role、Scheme),Scheme这种用的太少了,我们就简单讲解一下Policy和Role这两种方式。Policy和Role的核心就在于我们封装Token的时间添加的Claim对象。大家看到这里就会发现,其实Jwt的核心就是装包和拆包。网页请求Token的时间拿到了个包裹,网页发送Http的时间解开这个包裹。
我写了一会,感觉有点累了。这里有个别人写好的代码,有兴趣的自己去看吧。
   ASP.NET Core 6.0 添加 JWT 认证和授权
  简单的【角色授权】

获取不同权限的Token

获取不同权限的Token
  1. /// <summary>
  2. /// 获取Role = admin的Token
  3. /// </summary>
  4. /// <returns></returns>
  5. [HttpGet]
  6. public WebMsg GetJwtToken_Admin()
  7. {
  8.     var token = jwtHelper.GetJwtToken(new List<Claim>()
  9.     {
  10.         new Claim(ClaimTypes.Role,"admin")
  11.     });
  12.     return new WebMsg(token);
  13. }
  14. /// <summary>
  15. /// 获取Role = user
  16. /// </summary>
  17. /// <returns></returns>
  18. [HttpGet]
  19. public WebMsg GetJwtToken_User()
  20. {
  21.     var token = jwtHelper.GetJwtToken(new List<Claim>()
  22.     {
  23.         new Claim(ClaimTypes.Role,"user")
  24.     });
  25.     return new WebMsg(token);
  26. }
  27. /// <summary>
  28. /// 获取Role = admin和user
  29. /// </summary>
  30. /// <returns></returns>
  31. [HttpGet]
  32. public WebMsg GetJwtToken_UserAndAdmin()
  33. {
  34.     var token = jwtHelper.GetJwtToken(new List<Claim>()
  35.     {
  36.         new Claim(ClaimTypes.Role,"user"),
  37.         new Claim(ClaimTypes.Role,"admin")
  38.     });
  39.     return new WebMsg(token);
  40. }
复制代码
不同权限的jwt认证

  1. /// <summary>
  2. /// 需要role=admin
  3. /// </summary>
  4. /// <returns></returns>
  5. [HttpGet]
  6. [Authorize(Roles = "admin")]
  7. public WebMsg AdminGet()
  8. {
  9.     return new WebMsg("admin");
  10. }
  11. /// <summary>
  12. /// role=user
  13. /// </summary>
  14. /// <returns></returns>
  15. [HttpGet]
  16. [Authorize(Roles = "user")]
  17. public WebMsg UserGet()
  18. {
  19.     return new WebMsg("user");
  20. }
  21. /// <summary>
  22. /// role = admin或user
  23. /// </summary>
  24. /// <returns></returns>
  25. [HttpGet]
  26. [Authorize(Roles = "admin,user")]
  27. public WebMsg AdminOrUserGet()
  28. {
  29.     return new WebMsg("admin or user");
  30. }
  31. /// <summary>
  32. /// role=admin和user
  33. /// </summary>
  34. /// <returns></returns>
  35. [HttpGet]
  36. [Authorize(Roles = "admin")]
  37. [Authorize(Roles = "user")]
  38. public WebMsg AdminAndUserGet()
  39. {
  40.     return new WebMsg("admin and user");
  41. }
复制代码
这里推荐利用enum枚举范例,这样不会出现拼写错误
封装好的代码

  1. using Microsoft.IdentityModel.Tokens;
  2. using System.Text;
  3. namespace JtwTestWebApi.Models
  4. {
  5.     public class JwtConfig
  6.     {
  7.         /// <summary>
  8.         /// 密钥
  9.         /// </summary>
  10.         public string SecretKey { get; set; }
  11.         /// <summary>
  12.         /// 发布者
  13.         /// </summary>
  14.         public string Issuer { get; set; }
  15.         /// <summary>
  16.         /// 接受者
  17.         /// </summary>
  18.         public string Audience { get; set; }
  19.         /// <summary>
  20.         /// 过期时间(min)
  21.         /// </summary>
  22.         public int Expired { get; set; }
  23.         /// <summary>
  24.         /// 生效时间
  25.         /// </summary>
  26.         public DateTime NotBefore => DateTime.Now;
  27.         /// <summary>
  28.         /// 过期时间
  29.         /// </summary>
  30.         public DateTime Expiration => DateTime.Now.AddMinutes(Expired);
  31.         /// <summary>
  32.         /// 密钥Bytes
  33.         /// </summary>
  34.         private SecurityKey SigningKey => new SymmetricSecurityKey(Encoding.UTF8.GetBytes(SecretKey));
  35.         /// <summary>
  36.         /// 加密后的密钥,使用HmacSha256加密
  37.         /// </summary>
  38.         public SigningCredentials SigningCredentials =>
  39.             new SigningCredentials(SigningKey, SecurityAlgorithms.HmacSha256);
  40.         /// <summary>
  41.         /// 认证用的密钥
  42.         /// </summary>
  43.         public SymmetricSecurityKey SymmetricSecurityKey => new SymmetricSecurityKey(Encoding.UTF8.GetBytes(SecretKey));
  44.     }
  45. }
复制代码
  1. using JtwTestWebApi.Models;
  2. using Microsoft.AspNetCore.Authentication.JwtBearer;
  3. using Microsoft.IdentityModel.Tokens;
  4. using Microsoft.OpenApi.Models;
  5. using Newtonsoft.Json;
  6. using Swashbuckle.AspNetCore.SwaggerGen;
  7. using System.IdentityModel.Tokens.Jwt;
  8. using System.Security.Claims;
  9. using System.Text;
  10. namespace JtwTestWebApi.Utils
  11. {
  12.     public class JwtHelper
  13.     {
  14.         public JwtConfig JwtConfig { get; set; }
  15.         public JwtHelper()
  16.         {
  17.         }
  18.         /// <summary>
  19.         /// 添加Jwt服务
  20.         /// </summary>
  21.         public void AddJwtService(IServiceCollection services)
  22.         {
  23.             services.AddAuthentication(option =>
  24.             {
  25.                 //认证middleware配置
  26.                 option.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
  27.                 option.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
  28.             })
  29.             .AddJwtBearer(options =>
  30.             {
  31.                 options.TokenValidationParameters = new TokenValidationParameters
  32.                 {
  33.                     //Token颁发机构
  34.                     ValidIssuer = JwtConfig.Issuer,
  35.                     //颁发给谁
  36.                     ValidAudience = JwtConfig.Audience,
  37.                     //这里的key要进行加密
  38.                     IssuerSigningKey = JwtConfig.SymmetricSecurityKey,
  39.                     //是否验证Token有效期,使用当前时间与Token的Claims中的NotBefore和Expires对比
  40.                     ValidateLifetime = true,
  41.                     ValidateIssuer = true,
  42.                     ValidateAudience = true,
  43.                     ValidateIssuerSigningKey = true,
  44.                     RequireExpirationTime = true,
  45.                 };
  46.             });
  47.         }
  48.         /// <summary>
  49.         /// 最简单的JwtToken
  50.         /// </summary>
  51.         /// <returns></returns>
  52.         public string GetJwtToken()
  53.         {
  54.             var claims = new List<Claim>();
  55.             var jwtSecurityToken = new JwtSecurityToken(
  56.                     JwtConfig.Issuer,
  57.                     JwtConfig.Audience,
  58.                     claims,
  59.                     JwtConfig.NotBefore,
  60.                     JwtConfig.Expiration,
  61.                     JwtConfig.SigningCredentials
  62.                 );
  63.             var token = new JwtSecurityTokenHandler().WriteToken(jwtSecurityToken);
  64.             token = "Bearer " + token;
  65.             return token;
  66.         }
  67.         /// <summary>
  68.         /// 添加claims信息
  69.         /// </summary>
  70.         /// <param name="claims"></param>
  71.         /// <returns></returns>
  72.         public string GetJwtToken(List<Claim> claims)
  73.         {
  74.             var jwtSecurityToken = new JwtSecurityToken(
  75.                     JwtConfig.Issuer,
  76.                     JwtConfig.Audience,
  77.                     claims,
  78.                     JwtConfig.NotBefore,
  79.                     JwtConfig.Expiration,
  80.                     JwtConfig.SigningCredentials
  81.                 );
  82.             var token = new JwtSecurityTokenHandler().WriteToken(jwtSecurityToken);
  83.             token = "Bearer " + token;
  84.             return token;
  85.         }
  86.         /// <summary>
  87.         /// UserModel类Token
  88.         /// </summary>
  89.         /// <param name="user"></param>
  90.         /// <returns></returns>
  91.         public string GetJwtToken(JwtUserModel user)
  92.         {
  93.             var claims = new List<Claim>() {
  94.                 new Claim("UserId",user.UserId.ToString()),
  95.                 new Claim("UserName",user.UserName),
  96.                 new Claim("UserType",user.UserType.ToString()),
  97.             };
  98.             return GetJwtToken(claims);
  99.         }
  100.         /// <summary>
  101.         /// Swagger添加Jwt功能
  102.         /// </summary>
  103.         /// <param name="options"></param>
  104.         public static void SwaggerAddJwtHeader(SwaggerGenOptions options)
  105.         {
  106.             options.AddSecurityRequirement(new OpenApiSecurityRequirement()
  107.                 {
  108.                     {
  109.                         new OpenApiSecurityScheme
  110.                         {
  111.                             Reference = new OpenApiReference {
  112.                                 Type = ReferenceType.SecurityScheme,
  113.                                 Id = "Bearer",
  114.                             }
  115.                         },
  116.                     new string[] { }
  117.                     }
  118.                 });
  119.             options.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme
  120.             {
  121.                 Description = "JWT授权(数据将在请求头中进行传输) 在下方输入Bearer {token} 即可,注意两者之间有空格",
  122.                 Name = "Authorization",//jwt默认的参数名称
  123.                 In = ParameterLocation.Header,//jwt默认存放Authorization信息的位置(请求头中)
  124.                 Type = SecuritySchemeType.ApiKey,
  125.                 BearerFormat = "JWT",
  126.                 Scheme = "Bearer"
  127.             });
  128.         }
  129.         /// <summary>
  130.         /// 获取Jwt的信息
  131.         /// </summary>
  132.         /// <param name="request"></param>
  133.         /// <returns></returns>
  134.         public IEnumerable<Claim> Decode(HttpRequest request)
  135.         {
  136.             var authorization = request.Headers["Authorization"].ToString();
  137.             //因为我们的Jwt是自带【Bearer 】这个请求头的,所以去掉前面的头
  138.             var auth = authorization.Split(" ")[1];
  139.             var handler = new JwtSecurityTokenHandler();
  140.             //反解密,获取其中的Claims
  141.             var payload = handler.ReadJwtToken(auth).Payload;
  142.             var claims = payload.Claims;
  143.             return claims;
  144.         }
  145.         /// <summary>
  146.         /// 解析得到User
  147.         /// </summary>
  148.         /// <param name="request"></param>
  149.         /// <returns></returns>
  150.         public JwtUserModel DecodeToUser(HttpRequest request)
  151.         {
  152.             var claims = Decode(request);
  153.             var user = new JwtUserModel()
  154.             {
  155.                 UserId = claims.Where(t => t.Type == "UserId").First().Value,
  156.                 UserName = claims.Where(t => t.Type == "UserName").First().Value,
  157.                 UserType = claims.Where(t => t.Type == "UserType").First().Value
  158.             };
  159.             return user;
  160.         }
  161.     }
  162. }
复制代码
  1. namespace JtwTestWebApi.Models
  2. {
  3.     public class JwtUserModel
  4.     {
  5.         public string UserId { get; set; }
  6.         public string UserName { get; set; }
  7.         public string UserType { get; set; }
  8.     }
  9. }
复制代码
  1. using JtwTestWebApi.Models;using JtwTestWebApi.Utils;using Microsoft.Extensions.Configuration;using Microsoft.OpenApi.Models;using System.IdentityModel.Tokens.Jwt;using System.Reflection;namespace JtwTestWebApi{    public class Program    {        public static void Main(string[] args)        {            var builder = WebApplication.CreateBuilder(args);            var MyPolicy = "MyPolicy";            // Add services to the container.            builder.Services.AddControllers();            // Learn more about configuring Swagger/OpenAPI at https://aka.ms/aspnetcore/swashbuckle            builder.Services.AddEndpointsApiExplorer();            builder.Services.AddSwaggerGen();            //为了防止配套太多,代码杂乱。这里自定义了一个方法            AddMyService(builder);            var app = builder.Build();            // Configure the HTTP request pipeline.            if (app.Environment.IsDevelopment())            {                            }            app.UseSwagger();            app.UseSwaggerUI();            app.UseStatusCodePagesWithRedirects("/swagger/index.html");            app.UseHttpsRedirection();
  2.             app.UseAuthentication();//要在授权之前认证,这个和[Authorize]特性有关
  3.             app.UseAuthorization();
  4.             app.MapControllers();            app.Run();        }        /// <summary>        /// 为了防止代码过于痴肥,将新的配置放在这里写        /// </summary>        /// <param name="builder"></param>        public static void AddMyService(WebApplicationBuilder builder)        {            #region 默认的Webapi配置            builder.Services.AddCors(options =>            {                options.AddPolicy("MyPolicy", policy =>                {                    policy.AllowAnyHeader().AllowAnyOrigin().AllowAnyMethod();                });            });            builder.Services.AddSwaggerGen(options =>            {                options.SwaggerDoc("v1", new OpenApiInfo                {                    Version = "v1",                    Title = "API标题",                    Description = $"API形貌,v1版本"                });                var xmlFilename = $"{Assembly.GetExecutingAssembly().GetName().Name}.xml";                //IncludeXmlComments 第二参数 true 则表现 控制器 解释                options.IncludeXmlComments(Path.Combine(AppContext.BaseDirectory, xmlFilename), true);                JwtHelper.SwaggerAddJwtHeader(options);            });            #endregion             #region 添加Jwt服务            var jwtConfig = new JwtConfig();            builder.Configuration.Bind("JwtConfig",jwtConfig);            var jwtHelper = new JwtHelper() {                JwtConfig = jwtConfig            };            //将JwtHelper添加到Services内里            builder.Services.AddSingleton<JwtHelper>(jwtHelper);            jwtHelper.AddJwtService(builder.Services);            #endregion        }    }}
复制代码
appsettings.json中添加
  1.   "JwtConfig": {
  2.     "SecretKey": "lisheng741@qq.comlisheng741@qq.com",
  3.     "Issuer": "WebAppIssuer",
  4.     "Audience": "WebAppAudience",
  5.     "Expired": 30 // 过期时间(30min)
  6.   }
复制代码
总结

Jwt其实也不是特别难,就是第一次配置的时间容易被绕晕。Jwt的策略我暂时先跳过了,对于解决普通题目一般来说已经够用了。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。




欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/) Powered by Discuz! X3.4