【从0开始.NET CORE认证】-4 开启OAuth认证之JWT
系列
【从0开始.NET CORE认证】-2 使用.Net Core Identity和EF Core
回顾
还是回到第三篇文章中,我们在第三篇文章简单的介绍了一下以下内容
- 怎么样结合Identity认证给IdentityUser签发Claims
- 怎么样使用基于策略的权限验证
- 怎么样使用基于角色的权限验证
- 怎么样对IdentityUser进行Claim操作
其实第三篇并没有完全结束,只是没写完,有空再写。基于策略的权限验证能做很多有趣的事情。
但是本篇开始会开启OAuth认证
本次主要写一下内容
OAuth介绍
大家可以去百度,但是百度来的一大堆专业词汇,看的也非常迷惘!所以可以参考一下阮一峰大神的文章,关于解释OAuth是什么
我这里还是简单的画个图方便大家理解
1.这幅图就是传统的送货方式
上面这幅图会带来什么问题?
- 业主告诉了快递员密码,在业主密码没更改的情况下,也就是说快递员约等于业主。无论是否上下班都可以自由出入小区
- 快递员泄露了密码,会导致其他人也能冒充业主闯过小区门禁系统
- 业主如果每次收完货就更改密码,下次还是要把新密码提供给快递员。每次更改极其麻烦
所以为了解决问题,我们是不是中间加个流程,当快递员需要送货的时候,在小区门禁上提出申请,然后由业主同意,最后业主提供一个临时密码一样的东西给快递员,临时密码有有效期,1个小时就好了。这个问题是不是解决了
增加了345步骤,既可以保证小区的安全性,又可以完成送货
更多OAuth知识请参阅
JWT介绍
如果把上述流程应用到互联网开发中,现在开发模式大多属于前后端分离的状态,如果前端想要拿到后端的数据,后端说:你凭什么拿数据!依据我们前三篇讲的,我们可以用Cookies来证明自己。
但是Cookies有个局限就是无法应用于分布式场景。
所以引入了JWT的概念——JWT 全称Json Web Token,是一串字符串
JWT分成三部分
- 头部
- 载荷
- 签名
头部负责存储签名的算法和令牌的类型,载荷部分存储用户的个人信息。签名部分是对头部和载荷加密后生成的哈希字符。
头部和载荷负责base64加密,签名使用哈希,最终构成一个长度很长的字符串。
这个字符串就是快递员送货中的临时密码,在OAuth中也被称为access_token
.Net Core Identity接入OAuth生成JWT
.Net Core Identity已经实现了OAuth的框架,我们就用.Net Core Identity来实现一下OAuth
新建一个项目,名称为:OAuthServer,然后稍微修改一下使其成为一个MVC页面,增加一个Index页面和Secert页面,其中Secert页面需要授权访问
使用JWT需要引用以下扩展包
Microsoft.AspNetCore.Authentication.JwtBearer
在添加一个Login接口,负责颁发jwt
1 public IActionResult Login() 2 { 3 var claim = new[] 4 { 5 new Claim(JwtRegisteredClaimNames.Sub,"test"), 6 new Claim("test","test123") 7 }; 8 9 var keybytes = Encoding.UTF8.GetBytes(Constants.key); 10 var seckey = new SymmetricSecurityKey(keybytes); 11 var alorgthim = SecurityAlgorithms.HmacSha256; 12 var credential = new SigningCredentials(seckey, alorgthim); 13 14 var token = new JwtSecurityToken(Constants.Issuer, Constants.Audiance, claim, 15 notBefore: DateTime.Now, 16 expires: DateTime.Now.AddHours(2), 17 signingCredentials: credential 18 ); 19 20 var access_token = new JwtSecurityTokenHandler().WriteToken(token); 21 return Ok(new { access_token }); 22 }
其中Constrants类是我自定义的一个类
1 public class Constants 2 { 3 4 public const string Issuer = "http://localhost:8266"; 5 6 public const string Audiance = "http://localhost:8266"; 7 8 public const string key = "private_key_should_set_longer"; 9 10 }
运行,访问/Home/Login接口
发现是可以生成JWT格式的Token了。
把拿到的token放到jwt.io解析一下,看下是什么东西
可以看到,如我们上文介绍的一样,分成三个部分,头部,载荷和签名
使用JWT访问被保护的资源
这个时候需要使用一下测试工具POSTMAN,有关如果在http头部请求加入验证,请查阅百度,本处不再讲述
用户提交了一个jwt格式的token过来,我们肯定是需要进行核验的,如果我们不进行核验,用户随随便便就提交过来,岂不是保护资源约等于没保护?
在Startup.cs文件中修改一下代码
1 services.AddAuthentication("OAuth") 2 .AddJwtBearer("OAuth",config=> { 3 var keybytes = Encoding.UTF8.GetBytes(Constants.key); 4 var seckey = new SymmetricSecurityKey(keybytes); 5 config.TokenValidationParameters = new TokenValidationParameters 6 { 7 ValidIssuer = Constants.Issuer, 8 ValidAudience = Constants.Audiance, 9 IssuerSigningKey = seckey, 10 }; 11 });
然后我们用postman测试一下
可以发现成功访问。
把Token放到url连接里面
平常开发接口,有些时候为了方便,不会去对http的头部进行设置。所以会选择把token放到url参数里面,这种情况怎么处理呢?
只需要更改一下代码就行了
1 services.AddAuthentication("OAuth") 2 .AddJwtBearer("OAuth",config=> { 3 config.Events = new JwtBearerEvents() 4 { 5 OnMessageReceived = context => 6 { 7 if (context.Request.Query.ContainsKey("access_token")) 8 { 9 context.Token = context.Request.Query["access_token"]; 10 } 11 return Task.CompletedTask; 12 } 13 }; 14 var keybytes = Encoding.UTF8.GetBytes(Constants.key); 15 var seckey = new SymmetricSecurityKey(keybytes); 16 config.TokenValidationParameters = new TokenValidationParameters 17 { 18 ValidIssuer = Constants.Issuer, 19 ValidAudience = Constants.Audiance, 20 IssuerSigningKey = seckey, 21 }; 22 });
只需要侦听OnMessageReceived事件,当请求的url中包含access_token就把它的值赋给上下文中的token
运行看下:
可以发现,成功访问。
结束
好了,本章的JWT知识就到这里。