【从0开始.NET CORE认证】-4 开启OAuth认证之JWT

系列

【从0开始.NET CORE认证】-1 认识认证和授权

【从0开始.NET CORE认证】-2 使用.Net Core Identity和EF Core

【从0开始.NET CORE认证】-3 声明和策略授权

回顾

还是回到第三篇文章中,我们在第三篇文章简单的介绍了一下以下内容

  1. 怎么样结合Identity认证给IdentityUser签发Claims
  2. 怎么样使用基于策略的权限验证
  3. 怎么样使用基于角色的权限验证
  4. 怎么样对IdentityUser进行Claim操作

其实第三篇并没有完全结束,只是没写完,有空再写。基于策略的权限验证能做很多有趣的事情。

但是本篇开始会开启OAuth认证

本次主要写一下内容

 

 

 OAuth介绍

大家可以去百度,但是百度来的一大堆专业词汇,看的也非常迷惘!所以可以参考一下阮一峰大神的文章,关于解释OAuth是什么

OAuth2.0的一个简单解释——阮一峰

我这里还是简单的画个图方便大家理解

1.这幅图就是传统的送货方式

 

 

 上面这幅图会带来什么问题?

  1. 业主告诉了快递员密码,在业主密码没更改的情况下,也就是说快递员约等于业主。无论是否上下班都可以自由出入小区
  2. 快递员泄露了密码,会导致其他人也能冒充业主闯过小区门禁系统
  3. 业主如果每次收完货就更改密码,下次还是要把新密码提供给快递员。每次更改极其麻烦

所以为了解决问题,我们是不是中间加个流程,当快递员需要送货的时候,在小区门禁上提出申请,然后由业主同意,最后业主提供一个临时密码一样的东西给快递员,临时密码有有效期,1个小时就好了。这个问题是不是解决了

 

 

 增加了345步骤,既可以保证小区的安全性,又可以完成送货

更多OAuth知识请参阅

RFC-6749文档——英文版

RFC-6749文档——中文版

JWT介绍

如果把上述流程应用到互联网开发中,现在开发模式大多属于前后端分离的状态,如果前端想要拿到后端的数据,后端说:你凭什么拿数据!依据我们前三篇讲的,我们可以用Cookies来证明自己。

但是Cookies有个局限就是无法应用于分布式场景。

所以引入了JWT的概念——JWT 全称Json Web Token,是一串字符串

JWT分成三部分

  1. 头部
  2. 载荷
  3. 签名

头部负责存储签名的算法和令牌的类型,载荷部分存储用户的个人信息。签名部分是对头部和载荷加密后生成的哈希字符。

头部和载荷负责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知识就到这里。

 

posted @ 2020-02-23 20:35  寂寞空庭春欲晚  阅读(1001)  评论(1编辑  收藏  举报