WebAPI项目框架JWT权限验证

news/2024/7/7 18:29:28/文章来源:https://www.cnblogs.com/leon1128/p/18280526

JWT是什么?校验逻辑?授权过程?这里就不过多的阐述了,直接上代码

在appsettings.json中配置jwt参数的值

SecretKey必须大于16个字符

 1 {
 2   "Logging": {
 3     "LogLevel": {
 4       "Default": "Information",
 5       "Microsoft.AspNetCore": "Warning"
 6     }
 7   },
 8   "AllowedHosts": "*",
 9   "AppSettings": {
10     //数据库连接字符串
11     "ConnectionString": "server=192.168.132.131;uid=sa;pwd=6014359wQ@!;database=MagCoreDB",
12     "JwtSetting": {
13       "Issuer": "jwtIssuer", //颁发者
14       "Audience": "jwtAudience", //可以给哪些客户端使用
15       "SecretKey": "yehjsiwkjhuhgyehsnd" //加密Key
16     }
17   }
18 }

Nuget安装以下三个包:

在web.core.model中新建类TokenModel:

 1 /// <summary>
 2     /// 令牌
 3     /// </summary>
 4     public class TokenModel
 5     {
 6         /// <summary>
 7         /// Id
 8         /// </summary>
 9         public string Uid { get; set; }
10         /// <summary>
11         /// 角色
12         /// </summary>
13         public string Role { get; set; }
14 
15     }

新建JwtHelper.cs帮助类 

 1 public class JwtHelper
 2     {
 3         /// <summary>
 4         /// 颁发JWT字符串
 5         /// </summary>
 6         /// <param name="tokenModel"></param>
 7         /// <returns></returns>
 8         public static string IssueJwt(TokenModel tokenModel)
 9         {
10             //获取Appsetting配置
11             string iss = AppSettings.app(new string[] { "AppSettings", "JwtSetting", "Issuer" });
12             string aud = AppSettings.app(new string[] { "AppSettings", "JwtSetting", "Audience" });
13             string secret = AppSettings.app(new string[] { "AppSettings", "JwtSetting", "SecretKey" });
14 
15             //var claims = new Claim[] //old
16             var claims = new List<Claim>
17                 {
18                  /*
19                  * 特别重要:
20                    1、这里将用户的部分信息,比如 uid 存到了Claim 中,如果你想知道如何在其他地方将这个 uid从 Token 中取出来,请看下边的SerializeJwt() 方法,或者在整个解决方案,搜索这个方法,看哪里使用了!
21                    2、你也可以研究下 HttpContext.User.Claims ,具体的你可以看看 Policys/PermissionHandler.cs 类中是如何使用的。
22                  */
23                 new Claim(JwtRegisteredClaimNames.Jti, tokenModel.Uid.ToString()),
24                 new Claim(JwtRegisteredClaimNames.Iat, $"{new DateTimeOffset(DateTime.Now).ToUnixTimeSeconds()}"),
25                 new Claim(JwtRegisteredClaimNames.Nbf,$"{new DateTimeOffset(DateTime.Now).ToUnixTimeSeconds()}") ,
26                 //这个就是过期时间,目前是过期1000秒,可自定义,注意JWT有自己的缓冲过期时间
27                 new Claim (JwtRegisteredClaimNames.Exp,$"{new DateTimeOffset(DateTime.Now.AddSeconds(1000)).ToUnixTimeSeconds()}"),
28                 new Claim(ClaimTypes.Expiration, DateTime.Now.AddSeconds(1000).ToString()),
29                 new Claim(JwtRegisteredClaimNames.Iss,iss),
30                 new Claim(JwtRegisteredClaimNames.Aud,aud),
31 
32                };
33 
34             // 可以将一个用户的多个角色全部赋予;
35             claims.AddRange(tokenModel.Role.Split(',').Select(s => new Claim(ClaimTypes.Role, s)));
36 
37 
38 
39             //秘钥 (SymmetricSecurityKey 对安全性的要求,密钥的长度太短会报出异常)
40             var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(secret));
41             var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
42 
43             var jwt = new JwtSecurityToken(
44                 issuer: iss,
45                 claims: claims,
46                 signingCredentials: creds);
47 
48             var jwtHandler = new JwtSecurityTokenHandler();
49             var encodedJwt = jwtHandler.WriteToken(jwt);
50 
51             return encodedJwt;
52         }
53 
54         /// <summary>
55         /// 解析
56         /// </summary>
57         /// <param name="jwtStr"></param>
58         /// <returns></returns>
59         public static TokenModel SerializeJwt(string jwtStr)
60         {
61             var jwtHandler = new JwtSecurityTokenHandler();
62             JwtSecurityToken jwtToken = jwtHandler.ReadJwtToken(jwtStr);
63             object role;
64             try
65             {
66                 jwtToken.Payload.TryGetValue(ClaimTypes.Role, out role);
67             }
68             catch (Exception e)
69             {
70                 Console.WriteLine(e);
71                 throw;
72             }
73             var tm = new TokenModel
74             {
75                 Uid = jwtToken.Id.ToString(),
76                 Role = role != null ? role.ToString() : "",
77             };
78             return tm;
79         }
80     }

在HomeController中新建Login接口来获取Token

 1 /// <summary>
 2         /// 获取Token
 3         /// </summary>
 4         /// <param name="rolename"></param>
 5         /// <param name="password"></param>
 6         /// <returns></returns>
 7         [HttpGet]
 8         [AllowAnonymous]
 9         public async Task<IActionResult> Login(string rolename, string password)
10         {
11             string jwtStr = string.Empty;
12             bool suc = false;
13 
14             if (rolename != null && password != null)
15             {
16                 if (rolename != "Admin" && password != "123456")
17                 {
18                     jwtStr = "输入不正确!";
19                 }
20                 else
21                 {
22                     // 将用户id和角色名,作为单独的自定义变量封装进 token 字符串中。
23                     TokenModel tokenModel = new TokenModel { Uid = "1", Role = rolename };
24                     jwtStr = JwtHelper.IssueJwt(tokenModel);//登录,获取到一定规则的 Token 令牌
25                     suc = true;
26                 }
27             }
28             else
29             {
30                 jwtStr = "输入不能为空!";
31             }
32 
33             return Ok(new
34             {
35                 success = suc,
36                 token = jwtStr
37             });
38         }

运行项目,输入Admin,123456,获取Token:

JWT权限验证,就需要开启验证,然后输入token令牌,然后在SwaggerSetUp.cs的AddSwaggerSetup方法的AddSwaggerGen服务中,添加代码:

 1 services.AddSwaggerGen(c =>
 2             {
 3                 c.SwaggerDoc("V1", new OpenApiInfo
 4                 {
 5                     // {ApiName} 定义成全局变量,方便修改
 6                     Version = "V1",
 7                     Title = $"{ApiName} 接口文档——.NetCore 6.0",
 8                     Description = $"{ApiName} HTTP API V1",
 9                     //Contact = new OpenApiContact { Name = ApiName, Email = "Blog.Core@xxx.com", Url = new Uri("https://www.jianshu.com/u/94102b59cc2a") },
10                     //License = new OpenApiLicense { Name = ApiName, Url = new Uri("https://www.jianshu.com/u/94102b59cc2a") }
11                 });
12                 c.OrderActionsBy(o => o.RelativePath);
13 
14                 var xmlPath = Path.Combine(AppContext.BaseDirectory, "Mag.Core.API.xml");//这个就是刚刚配置的xml文件名
15                 c.IncludeXmlComments(xmlPath, true);//默认的第二个参数是false,这个是controller的注释,记得修改
16                 var xmlModelPath = Path.Combine(AppContext.BaseDirectory, "Mag.Core.Model.xml");//这个就是Model层的xml文件名
17                 c.IncludeXmlComments(xmlModelPath);
18 
19                 // 在header中添加token,传递到后台
20                 c.OperationFilter<SecurityRequirementsOperationFilter>();
21 
22                 #region Token绑定到ConfigureServices
23                 c.AddSecurityDefinition("oauth2", new OpenApiSecurityScheme
24                 {
25                     Description = "JWT授权(数据将在请求头中进行传输) 直接在下框中输入Bearer {token}(注意两者之间是一个空格)\"",
26                     Name = "Authorization",//jwt默认的参数名称
27                     In = ParameterLocation.Header,//jwt默认存放Authorization信息的位置(请求头中)
28                     Type = SecuritySchemeType.ApiKey
29                 });
30                 #endregion
31             });

运行项目,就可以看见JWT验证入口:

在SetUp文件夹里面新建注册方法AuthorizationSetup.cs

 1 public static class AuthorizationSetup
 2     {
 3         public static void AddAuthorizationSetup(this IServiceCollection services)
 4         {
 5             if (services == null) throw new ArgumentNullException(nameof(services));
 6 
 7             // 1【授权】、这个和上边的异曲同工,好处就是不用在controller中,写多个 roles 。
 8             // 然后这么写 [Authorize(Policy = "Admin")]
 9             services.AddAuthorization(options =>
10             {
11                 options.AddPolicy("User", policy => policy.RequireRole("User").Build());
12                 options.AddPolicy("System", policy => policy.RequireRole("System").Build());
13                 options.AddPolicy("SystemOrAdmin", policy => policy.RequireRole("Admin", "System"));
14 
15             });
16 
17             //读取配置文件
18             var symmetricKeyAsBase64 = AppSettings.app(new string[] { "AppSettings", "JwtSetting", "SecretKey" });
19             var keyByteArray = Encoding.ASCII.GetBytes(symmetricKeyAsBase64);
20             var signingKey = new SymmetricSecurityKey(keyByteArray);
21             var Issuer = AppSettings.app(new string[] { "AppSettings", "JwtSetting", "Issuer" });
22             var Audience = AppSettings.app(new string[] { "AppSettings", "JwtSetting", "Audience" });
23 
24 
25 
26             // 令牌验证参数
27             var tokenValidationParameters = new TokenValidationParameters
28             {
29                 ValidateIssuerSigningKey = true,
30                 IssuerSigningKey = signingKey,
31                 ValidateIssuer = true,
32                 ValidIssuer = Issuer,//发行人
33                 ValidateAudience = true,
34                 ValidAudience = Audience,//订阅人
35                 ValidateLifetime = true,
36                 ClockSkew = TimeSpan.FromSeconds(30),
37                 RequireExpirationTime = true,
38             };
39 
40             //2.1【认证】、core自带官方JWT认证
41             // 开启Bearer认证
42             services.AddAuthentication("Bearer")
43              // 添加JwtBearer服务
44              .AddJwtBearer(o =>
45              {
46                  o.TokenValidationParameters = tokenValidationParameters;
47                  o.Events = new JwtBearerEvents
48                  {
49                      OnAuthenticationFailed = context =>
50                      {
51                          // 如果过期,则把<是否过期>添加到,返回头信息中
52                          if (context.Exception.GetType() == typeof(SecurityTokenExpiredException))
53                          {
54                              context.Response.Headers.Add("Token-Expired", "true");
55                          }
56                          return Task.CompletedTask;
57                      }
58                  };
59              });
60 
61 
62 
63         }
64     }

在program.cs里面注册服务,开启服务

//jwt授权验证
builder.Services.AddAuthorizationSetup();
app.UseAuthentication();

在BaseApiController里面设置全局权限验证:

没有验证权限会提示401:

 

设置获取token的时候 [AllowAnonymous],无需验证:

 

设置测试方法:需要System的权限才能访问:

上面我们是用的Admin的权限,所以会提示403错误

 新增解析Token的方法:

 1 /// <summary>
 2         /// 解析Token
 3         /// </summary>
 4         /// <returns></returns>
 5         [HttpGet]
 6         [Authorize]
 7         public IActionResult ParseToken()
 8         {
 9             //需要截取Bearer 
10             var tokenHeader = HttpContext.Request.Headers["Authorization"].ToString().Replace("Bearer ", "");
11             var user = JwtHelper.SerializeJwt(tokenHeader);
12             return Ok(user);
13 
14         }

解析出来的role是Admin。

 

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

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

相关文章

2.SpringBoot快速上手

2.SpringBoot快速上手 SpringBoot介绍javaEE的开发经常会涉及到3个框架Spring ,SpringMVC,MyBatis.但是这三个框架配置极其繁琐,有大量的xml文件,spring Boot对之前的配置进行极大的简化Spring Boot 是由Pivotal团队提供的基于Spring的全新框架,简化Spring应用的初始搭建和…

RTMP协议

RTMP(Real-Time Messaging Protocol)是一个综合性的协议,不仅可以传输音视频数据,还可以传输信令控制指令。RTMP 使用 TCP 作为传输协议,可以直接在 TCP 连接上传输音视频数据,也可以传输控制指令,实现了音视频流的实时传输和控制。 与RTSP 不同,RTSP(Real-Time S…

yarn install 时显示 node_modules\esbuild: Command failed

可以找一找你的nodejs安装路径是不是中文的,如果是中文的换成英文应该就可以了(记得系统变量里也要改掉)

阿里云个人账号 创建docker仓库

1、创建阿里云账号 2、搜索“容器镜像服务”,进入,点击“管理控制台” 3、选择个人实例,这一步可能会让你创建registry密码(如果没有创建过的话),后面登录需要 4、创建命名空间5、创建镜像仓库 输入信息,点击下一步,选择本地仓库 6、进入管理页面 执行相关命令

Django3在网页上生成二维码

1.安装依赖包pip install django-qr-code2.在django,你项目的settings中,安装app 打开你项目的setting,找到INSTALLED_APPS ,在这里新加一条qr_code INSTALLED_APPS = [...,rest_framework,qr_code,... ] 3.在你打算渲染的html文档中,导入模板 {% load qr_code %}ps:如果…

Hackthebox bagel.dll 代码审计

利用ilspy将bagel.dll打开关于此目录有可以说的内容 目录解析 最上方的bagel是组装名字(assemble name) bagel_server 是命令空间(namespace) 下一级分支是类如File,Base,Handler,Orders等(class) 反序列化导致的命令执行漏洞代码审计思路 首先看主程序Bagel 1.通过明显的英…

2024/7/2 T1

题意:分析: 记 \(S_{i}\) 表示目前第 \(i\) 个集合里的元素个数。 集合之间互不区分,强制钦定必须满足 \(S_{i} \le S_{i+1}(i<k)\)。 经搜索发现,这样的状态数量最多约为 \(1.8 \times 10^5\)。 极差可以这样处理:将 \(a\) 排序,\(S_{i}\) 第一次加入某个元素 \(x\),…

Eplan插件 - 矩形修订云线

前言 在 CAD 中,矩形云线一直是设计师们用于标注修订区域或突出重要部分的得力工具。然而,在 Eplan 中,没有直接绘制矩形云线的功能。为了填补这一空白,开发了专门用于Eplan的矩形修订云线插件。 这款插件保留了Eplan绘制的习惯,可以简洁快速的框选出需要修订或者重点关注…

Nginx配置以及热升级

目录Nginx详解1. Nginx关键特性2. Nginx配置2.1 event2.2 http2.2.1 log_format2.2.2 sendfile2.2.3 tcp_nopush2.2.4 tcp_nodelay2.2.5 keepalive_timeout2.2.6 include2.2.7 default_type2.2.8 server3. 配置Nginx虚拟主机3.1 基于端口3.2 基于IP3.3 基于域名4. Location4.1 …

Python3学习之路~3.4 作业之对员工信息表实现增删改查操作

有以下员工信息表当然此表你在文件存储时可以这样表示1,Alex Li,22,13651054608,IT,2013-04-01 现需要对这个员工信息文件,实现增删改查操作可进行模糊查询,语法至少支持下面3种: select name,age from staff_table where age > 22 select * from staff_table where dep…

Python3学习之路~2.11 补充:Python输出字符串加颜色or背景色

格式:\033[二位数;1m字符串\033[0m 二位数为31-37,40-47(其他数字无效),其中:十位数3表示字颜色,4表示背景色个位数0-7分别表示 黑 红 绿 黄 蓝 紫 浅蓝 灰 示例代码:# 加颜色:31-37 print("\033[31;1mHello Python-31-红色字\033[0m") print("\033[32;…

【触想智能】工业平板电脑在新能源领域上的应用分析

工业平板电脑是一种具有高性能和稳定性的计算机设备,适用于在恶劣环境下进行数据采集、运营管理和现场操作。随着新能源技术的快速发展,工业平板电脑不断地得到应用,并且已成为新能源领域中的重要工具之一。本文将从四个方面探讨工业平板电脑在新能源领域中的应用。一、智能…

免费可视化工具在智慧物流中是如何被应用的?

在现代智慧物流中,免费可视化工具正扮演着越来越重要的角色。这些工具通过数据的可视化展示,使物流管理更加高效、透明和智能化。免费可视化工具可以将复杂的物流数据转换为直观的图表和图形,帮助管理者实时监控和分析物流运作情况,从而优化资源配置和提升物流效率。免费可…

一秒即懂财务报表勾稽关系

财务报表的勾稽关系!审计!审计试算平衡!算平衡表!项目经理!财务总监!会计!出纳6财务报表勾稽关系属于会计做账是否正确的要且快速的方法! 6财务人员对外提供报表是非常正常且频繁的情,股东要求,税局纳税申报,发行股票,发券,公司年度总结等等场合。 6而实际现状是,…

Redis Sentinal(哨兵模式详解)

参考文章 https://www.cnblogs.com/wzh2010/p/18030907 1、什么是哨兵模式 在实际生产环境中,服务器难免会遇到一些突发状况:服务器宕机,停电,硬件损坏等等,一旦发生,后果不堪设想。哨兵模式的核心还是主从模式的演变,只不过相对于主从模式,在主节点宕机导致不可写的情…

Profibus DP主站转Modbus网关连接智能化电表通讯

Profibus DP主站转Modbus网关(XD-MDPBM20),是实现不同工业通信协议之间互联互通的设备,主要将Profibus DP协议转换为Modbus协议,实现数据的双向传输。通过Profibus DP主站转Modbus网关(XD-MDPBM20),可以有效实现现场设备和控制系统之间的无缝连接,提高生产效率。Profi…

[XDCTF 2015]filemanager

[XDCTF 2015]filemanager ​/www.tar.gz​拿到源码 我直接在github上看了https://github.com/CTFTraining/xdctf_2015_filemanager common.inc.php将传入的所有参数使用addslashes转义函数 ​​ 然后分析upload.php 使用basename​函数确保文件名中没有目录路径,防止路径遍历攻…

解码未来城市:探秘数字孪生的奥秘

在科技日新月异的今天,"数字孪生"(Digital Twin)这一概念如同一颗璀璨的新星,照亮了智慧城市、智能制造等多个领域的前行之路。本文将深入浅出地解析数字孪生的定义、技术原理、应用场景及未来发展,带您一窥这股引领时代潮流的力量。数字孪生的定义数字孪生,简…

linux系统配置中文字体,playwright中文乱码

复制字段 从本地Windows (C:\Windows\Fonts ) 复制一个中文字体simsun.tcc 在Linux系统上安装字体 yum -y install fontconfig mkdir -p /usr/share/fonts/chinese cd /usr/share/fonts/chinese# 将simsun.tcc上传到/usr/share/fonts/chinese,并修改权限: chmod -R 755 /usr/…

transformer中的attention机制详解

transformer中用到的注意力机制包括self-attention(intra-attention)和传统的attention(cross-attention),本篇文章将在第一节简述这两者的差别,第二节详述self-attention机制,第三节介绍其实现 self-attention和attention的区别 传统attention机制 发生在decoder和enco…