您现在的位置是:网站首页> 编程资料编程资料
ASP.NET Core应用JWT进行用户认证及Token的刷新方案_实用技巧_
2023-05-24
348人已围观
简介 ASP.NET Core应用JWT进行用户认证及Token的刷新方案_实用技巧_
本文将通过实际的例子来演示如何在ASP.NET Core中应用JWT进行用户认证以及Token的刷新方案
一、什么是JWT?
JWT(json web token)基于开放标准(RFC 7519),是一种无状态的分布式的身份验证方式,主要用于在网络应用环境间安全地传递声明。它是基于JSON的,所以它也像json一样可以在.Net、JAVA、JavaScript,、PHP等多种语言使用。
为什么要使用JWT?
传统的Web应用一般采用Cookies+Session来进行认证。但对于目前越来越多的App、小程序等应用来说,它们对应的服务端一般都是RestFul 类型的无状态的API,再采用这样的的认证方式就不是很方便了。而JWT这种无状态的分布式的身份验证方式恰好符合这样的需求。
二、JWT的组成:
JWT是什么样子的呢?它就是下面这样的一段字符串:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8yMDA1LzA1L2lkZW50aXR5L2NsYWltcy9uYW1laWRlbnRpZmllciI6IjAwMiIsImh0dHA6Ly9zY2hlbWFzLnhtbHNvYXAub3JnL3dzLzIwMDUvMDUvaWRlbnRpdHkvY2xhaW1zL25hbWUiOiLmnY7lm5siLCJuYmYiOjE1NjU5MjMxMjIsImV4cCI6MTU2NTkyMzI0MiwiaXNzIjoiaHR0cDovL2xvY2FsaG9zdDo1NDIxNCIsImF1ZCI6Imh0dHA6Ly9sb2NhbGhvc3Q6NTQyMTUifQ.Mrta7nftmfXeo_igBVd4rl2keMmm0rg0WkqRXoVAeik
它是由三段“乱码”字符串通过两个“.”连接在一起组成。官网https://jwt.io/提供了它的验证方式
它的三个字符串分别对应了上图右侧的Header、Payload和Signature三部分。
Header
Header: { "alg": "HS256", "typ": "JWT" }标识加密方式为HS256,Token类型为JWT, 这段JSON通过Base64Url编码形成上例的第一个字符串
Payload
Payload是JWT用于信息存储部分,其中包含了许多种的声明(claims)。
可以自定义多个声明添加到Payload中,系统也提供了一些默认的类型
- iss (issuer):签发人
- exp (expiration time):过期时间
- sub (subject):主题
- aud (audience):受众
- nbf (Not Before):生效时间
- iat (Issued At):签发时间
- jti (JWT ID):编号
这部分通过Base64Url编码生成第二个字符串。
Signature
Signature是用于Token的验证。它的值类似这样的表达式:Signature = HMACSHA256( base64UrlEncode(header) + "." + base64UrlEncode(payload), secret),也就是说,它是通过将前两个字符串加密后生成的一个新字符串。
所以只有拥有同样加密密钥的人,才能通过前两个字符串获得同样的字符串,通过这种方式保证了Token的真实性。
三、认证流程
大概的流程是这样的:

- 认证服务器:用于用户的登录验证和Token的发放。
- 应用服务器:业务数据接口。被保护的API。
- 客户端:一般为APP、小程序等。
认证流程:
- 用户首先通过登录,到认证服务器获取一个Token。
- 在访问应用服务器的API的时候,将获取到的Token放置在请求的Header中。
- 应用服务器验证该Token,通过后返回对应的结果。
说明:这只是示例方案,实际项目中可能有所不同。
- 对于小型项目,可能认证服务和应用服务在一起。本例通过分开的方式来实现,使我们能更好的了解二者之间的认证流程。
- 对于复杂一些的项目,可能存在多个应用服务,用户获取到的Token可以在多个分布式服务中被认证,这也是JWT的优势之一。
关于JWT的文章很多,这里就不做过多介绍了。下面通过实际的例子来看一下 它是如何在ASP.NET Core 中应用的。
四、应用实例
上一节的图:“JWT的认证流程”中涉及到客户端、认证服务器、应用服务器三部分,下面通过示例来对这三部分进行模拟:
- 认证服务器:新建一个WebApi的解决方案,名为FlyLolo.JWT.Server。
- 应用服务器:新建一个WebApi的解决方案,名为FlyLolo.JWT.API。
- 客户端:这里用Fiddler发送请求做测试。
认证服务
首先新建一个ASP.NET Core 的解决方案WebApi的解决方案

将其命名为FlyLolo.JWT.Server。
首先新建一个TokenController用于登录和Token的发放:
[Route("api/[controller]")] public class TokenController : Controller { private ITokenHelper tokenHelper = null; public TokenController(ITokenHelper _tokenHelper) { tokenHelper = _tokenHelper; } [HttpGet] public IActionResult Get(string code, string pwd) { User user = TemporaryData.GetUser(code); if (null != user && user.Password.Equals(pwd)) { return Ok(tokenHelper.CreateToken(user)); } return BadRequest(); } }它有个名为Get的Action用于接收提交的用户名和密码,并进行验证,验证通过后,调用TokenHelper的CreateToken方法生成Token返回。
这里涉及到了User和TokenHelper两个类。
User相关:
public class User { public string Code { get; set; } public string Name { get; set; } public string Password { get; set; } }由于只是Demo,User类只含有以上三个字段。在TemporaryData类中做了User的模拟数据
////// 虚拟数据,模拟从数据库或缓存中读取用户 /// public static class TemporaryData { private static ListUsers = new List () { new User { Code = "001", Name = "张三", Password = "111111" }, new User { Code = "002", Name = "李四", Password = "222222" } }; public static User GetUser(string code) { return Users.FirstOrDefault(m => m.Code.Equals(code)); } }
这只是模拟数据,实际项目中应该从数据库或者缓存等读取。
TokenHelper:
public class TokenHelper : ITokenHelper { private IOptions _options; public TokenHelper(IOptions options) { _options = options; } public Token CreateToken(User user) { Claim[] claims = { new Claim(ClaimTypes.NameIdentifier,user.Code),new Claim(ClaimTypes.Name,user.Name) }; return CreateToken(claims); } private Token CreateToken(Claim[] claims) { var now = DateTime.Now;var expires = now.Add(TimeSpan.FromMinutes(_options.Value.AccessTokenExpiresMinutes)); var token = new JwtSecurityToken( issuer: _options.Value.Issuer, audience: _options.Value.Audience, claims: claims, notBefore: now, expires: expires, signingCredentials: new SigningCredentials(new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_options.Value.IssuerSigningKey)), SecurityAlgorithms.HmacSha256)); return new Token { TokenContent = new JwtSecurityTokenHandler().WriteToken(token), Expires = expires }; } } 通过CreateToken方法创建Token,这里有几个关键参数:
- issuer Token发布者
- Audience Token接受者
- expires 过期时间
- IssuerSigningKey 签名秘钥
对应的Token代码如下:
public class Token { public string TokenContent { get; set; } public DateTime Expires { get; set; } }这样通过TokenHelper的CreateToken方法生成了一个Token返回给了客户端。到现在来看,貌似所有的工作已经完成了。并非如此,我们还需要在Startup文件中做一些设置。
public class Startup { // 。。。。。。此处省略部分代码 public void ConfigureServices(IServiceCollection services) { //读取配置信息 services.AddSingleton(); services.Configure(Configuration.GetSection("JWT")); //启用JWT services.AddAuthentication(Options => { Options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; Options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; }). AddJwtBearer(); services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2); } public void Configure(IApplicationBuilder app, IHostingEnvironment env) { if (env.IsDevelopment()) { app.UseDeveloperExceptionPage(); } //启用认证中间件 app.UseAuthentication(); app.UseMvc(); } } 这里用到了配置信息,在appsettings.json中对认证信息做配置如下:
"JWT": { "Issuer": "FlyLolo", "Audience": "TestAudience", "IssuerSigningKey": "FlyLolo1234567890", "AccessTokenExpiresMinutes": "30" }运行这个项目,并通过Fidder以Get方式访问api/token?code=002&pwd=222222,返回结果如下:
{"tokenContent":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8yMDA1LzA1L2lkZW50aXR5L2NsYWltcy9uYW1laWRlbnRpZmllciI6IjAwMiIsImh0dHA6Ly9zY2hlbWFzLnhtbHNvYXAub3JnL3dzLzIwMDUvMDUvaWRlbnRpdHkvY2xhaW1zL25hbWUiOiLmnY7lm5siLCJuYmYiOjE1NjY3OTg0NzUsImV4cCI6MTU2NjgwMDI3NSwiaXNzIjoiRmx5TG9sbyIsImF1ZCI6IlRlc3RBdWRpZW5jZSJ9.BVf3gOuW1E9RToqKy8XXp8uIvZKL-lBA-q9fB9QTEZ4","expires":"2019-08-26T21:17:55.1183172+08:00"}
客户端登录成功并成功返回了一个Token,认证服务创建完成
应用服务
新建一个WebApi的解决方案,名为FlyLolo.JWT.API。
添加BookController用作业务API。
[Route("api/[controller]")] [Authorize] public class BookController : Controller { // GET: api/ [HttpGet] [AllowAnonymous] public IEnumerable Get() { return new string[] { "ASP", "C#" }; } // POST api/ [HttpPost] public JsonResult Post() { return new JsonResult("Create Book ..."); } } 对此Controller添加了[Authorize]标识,表示此Controller的Action被访问时需要进行认证,而它的名为Get的Action被标识了[AllowAnonymous],表示此Action的访问可以跳过认证。
在Startup文件中配置认证:
public class Startup { // 省略部分代码 public void ConfigureServices(IServiceCollection services) { #region 读取配置 JWTConfig config = new JWTConfig(); Configuration.GetSection("JWT").Bind(config); #endregion #region 启用JWT认证 services.AddAuthentication(options => { options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme; options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme; }). AddJwtBearer(options => { options.TokenValidationParameters = new TokenValidationParameters { ValidIssuer = config.Issuer, ValidAudience = config.Audience, IssuerSigningKey = new SymmetricSecurityKey(Encoding.UT
相关内容
- 关于.NET6 Minimal API的使用方式详解_实用技巧_
- .NET内存泄漏分析Windbg项目实例_实用技巧_
- .net 6精简版webapi教程及热重载、代码自动反编译演示_基础应用_
- .Net性能测试框架Crank的使用方法_基础应用_
- ASP.NET 使用 Dispose 释放资源的四种方法详细介绍_实用技巧_
- .NET Core读取配置文件的方法_基础应用_
- ASP.NET在VS2022中使用Dispose释放资源实例_基础应用_
- .NET HttpClient简单使用教程_实用技巧_
- .NET程序性能监控系统Elastic AMP的使用方法_实用技巧_
- .NET 6线程池ThreadPool实现概述_自学过程_
点击排行
本栏推荐
