.net5 core webapi项目实战之十五:身份验证(上篇)
本篇将在webapi项目中加入身份认证功能,仅对授权的用户提供服务,未授权的访问给出提示信息。
1. 在传统的web身份认证中,典型的认证过程是这样的:用户通过浏览器打开登录页,输入帐号/密码后提交,
Web服务器判断帐号/密码是否正确,如果正确会在服务器中生成一个Session对象标识用户身份,
同时在响应Header中设置对应的Cookie字符串传递回浏览器 ;
当用户再次访问页面的时候,浏览器发送的请求头会带上此Cookie字符串,Web服务器获取请求头中的Cookie字符串并解析,
然后与服务器中的Session对象比较,找出对应的Session,后续代码中就可以使用代表该用户身份的session信息了,如下图:
2. .net core webapi是以微服务的方式来提供数据和计算服务的,自然需要使用更加合适的身份验证模式,
为此微软为我们提供了JWT(JSON Web Token)的认证授权实现,这是一种基于token的鉴权机制,
它不需要在服务端用Session去保存用户的认证或会话信息,
只需要在请求/响应Header中加入签名后的字符串(称之为Token)就可以了,如下图:
可以看到已经不需要在Web服务器上保存Session并维护Session Map信息了。
3. JWT认证生成的Token字符串格式如下 :
jouf980uojfosadjdfhaksd.sf23er4wehyuty3fasdf2sdzxz7xcvghret2kko9werdfartyy.cfg54dskj7nyuhj89sdfghj
它由三部分组成,分别是头信息、有效载荷、签名,中间以(.)分隔,每段的作用如下:
第一部分:header(头信息)
编码前的 header 信息包含算法(默认是 HMAC SHA256)和token类型定义(采用json格式,形式如下),
1 { 2 "alg": "HS256", 3 "typ": "JWT" 4 }
对此json对象进行Base64URL加密生成一个字符串,形如 "jouf980uojfosadjdfhaksd" 。
第二部分:Payload(有效载荷)
包含Claims(声明),用来存放实际需要传递的数据,也是一个 JSON 对象,如下:
1 { 2 "sub": "testabcde", 3 "exp":"2020/01/02 09:20:39", 4 "jti":1034758934 5 "userid":9527 6 "username": "John Doe", 7 }
对此json对象进行Base64URL加密生成一个字符串,形如 "sf23er4wehyuty3fasdf2sdzxz7xcvghret2kko9werdfartyy" 。
Claims 中的字段名称可以使用官方推荐的名称也可以自己定义,如下表所示:
序号 | 名称 | 描述 | 类别 |
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 这两个包。
安装后在解决方案资源管理器中就可以看到这2个包了,如下:
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认证服务。
在终结点 ManageUsers( ) 上使用Jwt认证服务之前,我们先访问一下API,看Jwt认证生效前是什么效果。
打开POSTMAN,访问http://localhost:52384/api/users,结果如下:
可以看到在终结点 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,结果如下:
此时响应的是"401 Unauthorized" 没有授权,并且在响应Header中多了一个"WWW-Authenticate"的KEY,Value="Bearer",Jwt身份认证已经生效了。
另:如果要对UsersController中所有终结点都启用Jwt身份认证,只需要在UsersController这个类名上加[Authorize]属性
就可以了。
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列(二):开始使用ML.NET
· 记一次.NET内存居高不下排查解决与启示
· 探究高空视频全景AR技术的实现原理
· 理解Rust引用及其生命周期标识(上)
· 浏览器原生「磁吸」效果!Anchor Positioning 锚点定位神器解析
· 全程不用写代码,我用AI程序员写了一个飞机大战
· DeepSeek 开源周回顾「GitHub 热点速览」
· 记一次.NET内存居高不下排查解决与启示
· MongoDB 8.0这个新功能碉堡了,比商业数据库还牛
· .NET10 - 预览版1新功能体验(一)