.net5 core webapi项目实战之十五:身份验证

本篇将在webapi项目中加入身份认证功能,仅对授权的用户提供服务,未授权的访问给出提示信息。

 

1. 在传统的web身份认证中,典型的认证过程是这样的:用户通过浏览器打开登录页,输入帐号/密码后提交,

Web服务器判断帐号/密码是否正确,如果正确会在服务器中生成一个Session对象标识用户身份,

同时在响应Header中设置对应的Cookie字符串传递回浏览器 ;

当用户再次访问页面的时候,浏览器发送的请求头会带上此Cookie字符串,Web服务器获取请求头中的Cookie字符串并解析,

然后与服务器中的Session对象比较,找出对应的Session,后续代码中就可以使用代表该用户身份的session信息了,如下图:

.net5 core webapi项目实战之十五:身份验证

 

2. .net core webapi是以微服务的方式来提供数据和计算服务的,自然需要使用更加合适的身份验证模式,

为此微软为我们提供了基于JWT(JSON Web Token)的认证授权实现,这是一种基于token的鉴权机制,

它不需要在服务端用Session去保存用户的认证或会话信息,

只需要在请求/响应Header中加入签名后的字符串(称之为Token)就可以了,如下图:

.net5 core webapi项目实战之十五:身份验证

可以看到已经不需要在Web服务器上单独保存Session信息了。

 

3. JWT认证生成的Token字符串格式如下 :

jouf980uojfosadjdfhaksd.sf23er4wehyuty3fasdf2sdzxz7xcvghret2kko9werdfartyy.cfg54dskj7nyuhj89sdfghj

JWT由三部分组成,分别是头信息、有效载荷、签名,中间以(.)分隔,每段的作用如下:

第一部分:header(头信息)

包含算法(默认是 HMAC SHA256)和token类型定义(采用json格式,形式如下),

对此json进行Base64URL加密生成一个字符串,形如 "jouf980uojfosadjdfhaksd" 。

1 {
2  "alg": "HS256",
3  "typ": "JWT"
4  }

第二部分:Payload(有效载荷)

用来存放实际需要传递的数据,也是一个 JSON 对象并进行Base64URL加密生成一个字符串,

形如 "sf23er4wehyuty3fasdf2sdzxz7xcvghret2kko9werdfartyy" 。

1  {
2    "sub": "testabcde",
3    "exp":"2020/01/02 09:20:39", 
4    "jti":1034758934
5    "userid":9527     
6    "username": "John Doe",
7  }

 字段名称可以使用官方推荐的名称也可以自己定义,如下表所示:

序号 名称 描述 预定义
1 iss (issuer) 签发人 官方字段
2 exp (expiration time) 过期时间 官方字段
3 sub (subject) 主题 官方字段
4 aud (audience) 受众 官方字段
5 nbf (Not Before) 生效时间 官方字段
6 iat (Issued At) 签发时间 官方字段
7 jti (JWT ID) 编号 官方字段
8 xxxx 用户自定义 私有字段
... xxxx 用户自定义 私有字段
n xxxx 用户自定义 私有字段

第三部分:Signature(签名),先将 "编码过的header字符串"和"编码过的payload字符串" 用 "." 拼接起来,

然后使用 Header 里面指定的签名算法(默认是 HMAC SHA256)配合指定的密钥(secret)对它们签名,

最后将签名的结果用Base64URL加密生成一个字符串,形如 "cfg54dskj7nyuhj89sdfghj" 。

 

注:因为Base64URL实际是对字符串做了一下转换,大部分语言都是可以对其进行解密的,

所以对于敏感数据的传递需要先加密,加密方式可以参考本系列第十二篇。

 

4. .net5 core webapi中的编码实现。

有了前面对原理的了解再编码实现就比较简单了,步骤如下:

4.1 先安装 System.IdentityModel.Tokens.Jwt 和 Microsoft.AspNetCore.Authentication.JwtBearer  这两个包。

.net5 core webapi项目实战之十五:身份验证

.net5 core webapi项目实战之十五:身份验证

安装后在解决方案资源管理器中就可以看到这2个包了,如下:

.net5 core webapi项目实战之十五:身份验证

 4.2 在Startup类的 ConfigureServices( ) 方法中配置JWT,增加如下代码(红色标注):

 1         public void ConfigureServices(IServiceCollection services)
 2         {
 3             services.AddControllers();
 4      
 5             services.AddScoped<IUserDao, MySqlUserDao>();
 6 
 7             services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme).AddJwtBearer();
 8   
 9         }

4.3 在 Startup 类的 Configure( ) 方法中启用JWT,代码如下(红色标注):

 1         public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILoggerFactory loggerFactory)
 2         {
 3             if (env.IsDevelopment())
 4             {
 5                 app.UseDeveloperExceptionPage();
 6 
 7             } 
 8 
 9             loggerFactory.AddFile("Logs/log{Date}.txt");
10 
11             app.UseRouting();
12 
13             app.UseAuthentication();
14 
15             app.UseAuthorization();           
16 
17             app.UseEndpoints(endpoints =>
18             {
19                 endpoints.MapControllers();
20             });
21         }

4.4 在UsersController.cs中使用Jwt认证服务。

在使用Jwt认证服务之前,我们先访问一下API,看Jwt认证是否已经生效。

打开POSTMAN,访问http://localhost:52384/api/users,结果如下:

.net5 core webapi项目实战之十五:身份验证

可以看到在终结点 ManageUsers( ) 没有使用Jwt认证时,可以正常访问。

 

在UsersController.cs中添加引用 using Microsoft.AspNetCore.Authorization;

然后在终结点ManageUsers()上加[Authorize]属性启用Jwt认证服务,代码如下(红色标注):

1         [HttpGet]
2         [Authorize]
3         public ContentResult ManageUsers()
4         {
5             //...
6         }    

 重新编译项目,然后在POSTMAN中访问 http://localhost:52384/api/users,结果如下:

.net5 core webapi项目实战之十五:身份验证

此时响应的是"401 Unauthorized" 没有授权,Jwt身份认证已经生效了。

另:如果要对UsersController中所有终结点都启用Jwt身份认证,只需要在UsersController类名上加[Authorize]属性就可以了。

 

上一篇:ASP.NET Core WebApi版本控制


下一篇:ASP.NET WebAPI如何实现文件的上传实战演练