本文将通过实际的例子来演示如何在ASP.NET Core中应用JWT进行用户认证以及Token的刷新方案(ASP.NET Core 系列目录

一、什么是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:

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

标识加密方式为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的真实性。

三、认证流程

大概的流程是这样的:

  1. 认证服务器:用于用户的登录验证和Token的发放。
  2. 应用服务器:业务数据接口。被保护的API。
  3. 客户端:一般为APP、小程序等。

认证流程:

  1. 用户首先通过登录,到认证服务器获取一个Token。
  2. 在访问应用服务器的API的时候,将获取到的Token放置在请求的Header中。
  3. 应用服务器验证该Token,通过后返回对应的结果。

说明:这只是示例方案,实际项目中可能有所不同。

  1. 对于小型项目,可能认证服务和应用服务在一起。本例通过分开的方式来实现,使我们能更好的了解二者之间的认证流程。
  2. 对于复杂一些的项目,可能存在多个应用服务,用户获取到的Token可以在多个分布式服务中被认证,这也是JWT的优势之一。

关于JWT的文章很多,这里就不做过多介绍了。下面通过实际的例子来看一下 它是如何在ASP.NET Core 中应用的。

四、应用实例

上一节的图:“JWT的认证流程”中涉及到客户端、认证服务器、应用服务器三部分,下面通过示例来对这三部分进行模拟:

  1. 认证服务器:新建一个WebApi的解决方案,名为FlyLolo.JWT.Server。
  2. 应用服务器:新建一个WebApi的解决方案,名为FlyLolo.JWT.API。
  3. 客户端:这里用Fiddler发送请求做测试。

认证服务

首先新建一个ASP.NET Core 的解决方案WebApi的解决方案

将其命名为FlyLolo.JWT.Server。

首先新建一个TokenController用于登录和Token的发放:

  1. [Route("api/[controller]")]
  2. public class TokenController : Controller
  3. {
  4. private ITokenHelper tokenHelper = null;
  5. public TokenController(ITokenHelper _tokenHelper)
  6. {
  7. tokenHelper = _tokenHelper;
  8. }
  9. [HttpGet]
  10. public IActionResult Get(string code, string pwd)
  11. {
  12. User user = TemporaryData.GetUser(code);
  13. if (null != user && user.Password.Equals(pwd))
  14. {
  15. return Ok(tokenHelper.CreateToken(user));
  16. }
  17. return BadRequest();
  18. }
  19. }

它有个名为Get的Action用于接收提交的用户名和密码,并进行验证,验证通过后,调用TokenHelper的CreateToken方法生成Token返回。

这里涉及到了User和TokenHelper两个类。

User相关:

  1. public class User
  2. {
  3. public string Code { get; set; }
  4. public string Name { get; set; }
  5. public string Password { get; set; }
  6. }

由于只是Demo,User类只含有以上三个字段。在TemporaryData类中做了User的模拟数据

  1. /// <summary>
  2. /// 虚拟数据,模拟从数据库或缓存中读取用户
  3. /// </summary>
  4. public static class TemporaryData
  5. {
  6. private static List<User> Users = new List<User>() { new User { Code = "", Name = "张三", Password = "" }, new User { Code = "", Name = "李四", Password = "" } };
  7.  
  8. public static User GetUser(string code)
  9. {
  10. return Users.FirstOrDefault(m => m.Code.Equals(code));
  11. }
  12. }

这只是模拟数据,实际项目中应该从数据库或者缓存等读取。

TokenHelper:

  1. public class TokenHelper : ITokenHelper
  2. {
  3. private IOptions<JWTConfig> _options;
  4. public TokenHelper(IOptions<JWTConfig> options)
  5. {
  6. _options = options;
  7. }
  8.  
  9. public Token CreateToken(User user)
  10. {
  11. Claim[] claims = { new Claim(ClaimTypes.NameIdentifier,user.Code),new Claim(ClaimTypes.Name,user.Name) };
  12.  
  13. return CreateToken(claims);
  14. }
  15. private Token CreateToken(Claim[] claims)
  16. {
  17. var now = DateTime.Now;var expires = now.Add(TimeSpan.FromMinutes(_options.Value.AccessTokenExpiresMinutes));
  18. var token = new JwtSecurityToken(
  19. issuer: _options.Value.Issuer,
  20. audience: _options.Value.Audience,
  21. claims: claims,
  22. notBefore: now,
  23. expires: expires,
  24. signingCredentials: new SigningCredentials(new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_options.Value.IssuerSigningKey)), SecurityAlgorithms.HmacSha256));
  25. return new Token { TokenContent = new JwtSecurityTokenHandler().WriteToken(token), Expires = expires };
  26. }
  27. }

通过CreateToken方法创建Token,这里有几个关键参数:

  1. issuer            Token发布者
  2. Audience      Token接受者
  3. expires          过期时间
  4. IssuerSigningKey  签名秘钥

对应的Token代码如下:

  1. public class Token
  2. {
  3. public string TokenContent { get; set; }
  4.  
  5. public DateTime Expires { get; set; }
  6. }

这样通过TokenHelper的CreateToken方法生成了一个Token返回给了客户端。到现在来看,貌似所有的工作已经完成了。并非如此,我们还需要在Startup文件中做一些设置。

  1. public class Startup
  2. {
    // 。。。。。。此处省略部分代码
  3. public void ConfigureServices(IServiceCollection services)
  4. {
    //读取配置信息
  5. services.AddSingleton<ITokenHelper, TokenHelper>();
  6. services.Configure<JWTConfig>(Configuration.GetSection("JWT"));
  7. //启用JWT
  8. services.AddAuthentication(Options =>
  9. {
  10. Options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
  11. Options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
  12. }).
  13. AddJwtBearer();
  14. services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
  15. }
  16.  
  17. public void Configure(IApplicationBuilder app, IHostingEnvironment env)
  18. {
  19. if (env.IsDevelopment())
  20. {
  21. app.UseDeveloperExceptionPage();
  22. }
    //启用认证中间件
  23. app.UseAuthentication();
  24. app.UseMvc();
  25. }
  26. }

这里用到了配置信息,在appsettings.json中对认证信息做配置如下:

  1. "JWT": {
  2. "Issuer": "FlyLolo",
  3. "Audience": "TestAudience",
  4. "IssuerSigningKey": "FlyLolo1234567890",
  5. "AccessTokenExpiresMinutes": ""
  6. }

运行这个项目,并通过Fidder以Get方式访问api/token?code=002&pwd=222222,返回结果如下:

  1. {"tokenContent":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8
    yMDA1LzA1L2lkZW50aXR5L2NsYWltcy9uYW1laWRlbnRpZmllciI6IjAwMiIsImh0dHA6Ly9zY2hlbWFzLnhtbHNvYXAub3JnL
    3dzLzIwMDUvMDUvaWRlbnRpdHkvY2xhaW1zL25hbWUiOiLmnY7lm5siLCJuYmYiOjE1NjY3OTg0NzUsImV4cCI6MTU2NjgwMDI
    3NSwiaXNzIjoiRmx5TG9sbyIsImF1ZCI6IlRlc3RBdWRpZW5jZSJ9.BVf3gOuW1E9RToqKy8XXp8uIvZKL-lBA-q9fB9QTEZ4",
    "expires":"2019-08-26T21:17:55.1183172+08:00"}

客户端登录成功并成功返回了一个Token,认证服务创建完成

应用服务

新建一个WebApi的解决方案,名为FlyLolo.JWT.API。

添加BookController用作业务API。

  1. [Route("api/[controller]")]
  2. [Authorize]
  3. public class BookController : Controller
  4. {
  5. // GET: api/<controller>
  6. [HttpGet]
  7. [AllowAnonymous]
  8. public IEnumerable<string> Get()
  9. {
  10. return new string[] { "ASP", "C#" };
  11. }
  12.  
  13. // POST api/<controller>
  14. [HttpPost]
  15. public JsonResult Post()
  16. {
  17. return new JsonResult("Create Book ...");
  18. }
  19. }

对此Controller添加了[Authorize]标识,表示此Controller的Action被访问时需要进行认证,而它的名为Get的Action被标识了[AllowAnonymous],表示此Action的访问可以跳过认证。

在Startup文件中配置认证:

  1. public class Startup
  2. {
  3. // 省略部分代码
  4. public void ConfigureServices(IServiceCollection services)
  5. {
  6. #region 读取配置
  7. JWTConfig config = new JWTConfig();
  8. Configuration.GetSection("JWT").Bind(config);
  9. #endregion
  10.  
  11. #region 启用JWT认证
  12. services.AddAuthentication(options =>
  13. {
  14. options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
  15. options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
  16. }).
  17. AddJwtBearer(options =>
  18. {
  19. options.TokenValidationParameters = new TokenValidationParameters
  20. {
  21. ValidIssuer = config.Issuer,
  22. ValidAudience = config.Audience,
  23. IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(config.IssuerSigningKey)),
  24. ClockSkew = TimeSpan.FromMinutes(1)
  25. };
  26. });
  27. #endregion
  28.  
  29. services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
  30. }
  31.  
  32. // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
  33. public void Configure(IApplicationBuilder app, IHostingEnvironment env)
  34. {
  35. if (env.IsDevelopment())
  36. {
  37. app.UseDeveloperExceptionPage();
  38. }
  39. app.UseAuthentication();
  40. app.UseMvc();
  41. }
  42. }

这里同样用到了配置:

  1. public class JWTConfig
  2. {
  3. public string Issuer { get; set; }
  4. public string Audience { get; set; }
  5. public string IssuerSigningKey { get; set; }
  6. public int AccessTokenExpiresMinutes { get; set; }
  7. }

appsettings.json:

  1. "JWT": {
  2. "Issuer": "FlyLolo",
  3. "Audience": "TestAudience",
  4. "IssuerSigningKey": "FlyLolo1234567890",
  5. "AccessTokenExpiresMinutes": ""
  6. }

关于JWT认证,这里通过options.TokenValidationParameters对认证信息做了设置,ValidIssuer、ValidAudience、IssuerSigningKey这三个参数用于验证Token生成的时候填写的Issuer、Audience、IssuerSigningKey,所以值要和生成Token时的设置一致。

ClockSkew默认值为5分钟,它是一个缓冲期,例如Token设置有效期为30分钟,到了30分钟的时候是不会过期的,会有这么个缓冲时间,也就是35分钟才会过期。为了方便测试(不想等太长时间),这里我设置了1分钟。

TokenValidationParameters还有一些其他参数,在它的构造方法中已经做了默认设置,代码如下:

  1. public TokenValidationParameters()
  2. {
  3. RequireExpirationTime = true;
  4. RequireSignedTokens = true;
  5. SaveSigninToken = false;
  6. ValidateActor = false;
  7. ValidateAudience = true; //是否验证接受者
  8. ValidateIssuer = true; //是否验证发布者
  9. ValidateIssuerSigningKey = false; //是否验证秘钥
  10. ValidateLifetime = true; //是否验证过期时间
  11. ValidateTokenReplay = false;
  12. }

访问api/book,正常返回了结果

  1. ["ASP","C#"]

通过POST方式访问,返回401错误。

这就需要使用获取到的Toke了,如下图方式再次访问

添加了“Authorization: bearer Token内容”这样的Header,可以正常访问了。

至此,简单的JWT认证示例就完成了,代码地址https://github.com/FlyLolo/JWT.Demo/releases/tag/1.0

这里可能会有个疑问,例如:

1.Token被盗了怎么办?

答: 在启用Https的情况下,Token被放在Header中还是比较安全的。另外Token的有效期不要设置过长。例如可以设置为1小时(微信公众号的网页开发的Token有效期为2小时)。

2. Token到期了如何处理?

答:理论上Token过期应该是跳到登录界面,但这样太不友好了。可以在后台根据Token的过期时间定期去请求新的Token。下一节来演示一下Token的刷新方案。

五、Token的刷新

为了使客户端能够获取到新的Token,对上文的例子进行改造,大概思路如下:

  1. 用户登录成功的时候,一次性给他两个Token,分别为AccessToken和RefreshToken,AccessToken用于正常请求,也就是上例中原有的Token,RefreshToken作为刷新AccessToken的凭证。
  2. AccessToken的有效期较短,例如一小时,短一点安全一些。RefreshToken有效期可以设置长一些,例如一天、一周等。
  3. 当AccessToken即将过期的时候,例如提前5分钟,客户端利用RefreshToken请求指定的API获取新的AccessToken并更新本地存储中的AccessToken。

所以只需要修改FlyLolo.JWT.Server即可。

首先修改Token的返回方案,新增一个Model

  1. public class ComplexToken
  2. {
  3. public Token AccessToken { get; set; }
  4. public Token RefreshToken { get; set; }
  5. }

包含AccessToken和RefreshToken,用于用户登录成功后的Token结果返回。

修改 appsettings.json,添加两个配置项:

  1. "RefreshTokenAudience": "RefreshTokenAudience",
  2. "RefreshTokenExpiresMinutes": "" //60*24*7

RefreshTokenExpiresMinutes用于设置RefreshToken的过期时间,这里设置了7天。RefreshTokenAudience用于设置RefreshToken的接受者,与原Audience值不一致,作用是使RefreshToken不能用于访问应用服务的业务API,而AccessToken不能用于刷新Token。

修改TokenHelper:

  1. public enum TokenType
  2. {
  3. AccessToken = ,
  4. RefreshToken =
  5. }
  6. public class TokenHelper : ITokenHelper
  7. {
  8. private IOptions<JWTConfig> _options;
  9. public TokenHelper(IOptions<JWTConfig> options)
  10. {
  11. _options = options;
  12. }
  13.  
  14. public Token CreateAccessToken(User user)
  15. {
  16. Claim[] claims = new Claim[] { new Claim(ClaimTypes.NameIdentifier, user.Code), new Claim(ClaimTypes.Name, user.Name) };
  17.  
  18. return CreateToken(claims, TokenType.AccessToken);
  19. }
  20.  
  21. public ComplexToken CreateToken(User user)
  22. {
  23. Claim[] claims = new Claim[] { new Claim(ClaimTypes.NameIdentifier, user.Code), new Claim(ClaimTypes.Name, user.Name)
  24. //下面两个Claim用于测试在Token中存储用户的角色信息,对应测试在FlyLolo.JWT.API的两个测试Controller的Put方法,若用不到可删除
  25. , new Claim(ClaimTypes.Role, "TestPutBookRole"), new Claim(ClaimTypes.Role, "TestPutStudentRole")
  26. };
  27.  
  28. return CreateToken(claims);
  29. }
  30.  
  31. public ComplexToken CreateToken(Claim[] claims)
  32. {
  33. return new ComplexToken { AccessToken = CreateToken(claims, TokenType.AccessToken), RefreshToken = CreateToken(claims, TokenType.RefreshToken) };
  34. }
  35.  
  36. /// <summary>
  37. /// 用于创建AccessToken和RefreshToken。
  38. /// 这里AccessToken和RefreshToken只是过期时间不同,【实际项目】中二者的claims内容可能会不同。
  39. /// 因为RefreshToken只是用于刷新AccessToken,其内容可以简单一些。
  40. /// 而AccessToken可能会附加一些其他的Claim。
  41. /// </summary>
  42. /// <param name="claims"></param>
  43. /// <param name="tokenType"></param>
  44. /// <returns></returns>
  45. private Token CreateToken(Claim[] claims, TokenType tokenType)
  46. {
  47. var now = DateTime.Now;
  48. var expires = now.Add(TimeSpan.FromMinutes(tokenType.Equals(TokenType.AccessToken) ? _options.Value.AccessTokenExpiresMinutes : _options.Value.RefreshTokenExpiresMinutes));//设置不同的过期时间
  49. var token = new JwtSecurityToken(
  50. issuer: _options.Value.Issuer,
  51. audience: tokenType.Equals(TokenType.AccessToken) ? _options.Value.Audience : _options.Value.RefreshTokenAudience,//设置不同的接受者
  52. claims: claims,
  53. notBefore: now,
  54. expires: expires,
  55. signingCredentials: new SigningCredentials(new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_options.Value.IssuerSigningKey)), SecurityAlgorithms.HmacSha256));
  56. return new Token { TokenContent = new JwtSecurityTokenHandler().WriteToken(token), Expires = expires };
  57. }
  58.  
  59. public Token RefreshToken(ClaimsPrincipal claimsPrincipal)
  60. {
  61. var code = claimsPrincipal.Claims.FirstOrDefault(m => m.Type.Equals(ClaimTypes.NameIdentifier));
  62. if (null != code )
  63. {
  64. return CreateAccessToken(TemporaryData.GetUser(code.Value.ToString()));
  65. }
  66. else
  67. {
  68. return null;
  69. }
  70. }
  71. }

在登录后,生成两个Token返回给客户端。在TokenHelper添加了一个RefreshToken方法,用于生成新的AccessToken。对应在TokenController中添加一个名为Post的Action,用于调用这个RefreshToken方法刷新Token

  1. [HttpPost]
  2. [Authorize]
  3. public IActionResult Post()
  4. {
  5. return Ok(tokenHelper.RefreshToken(Request.HttpContext.User));
  6. }

这个方法添加了[Authorize]标识,说明调用它需要RefreshToken认证通过。既然启用了认证,那么在Startup文件中需要像上例的业务API一样做JWT的认证配置。

  1. public void ConfigureServices(IServiceCollection services)
  2. {
  3. #region 读取配置信息
  4. services.AddSingleton<ITokenHelper, TokenHelper>();
  5. services.Configure<JWTConfig>(Configuration.GetSection("JWT"));
  6. JWTConfig config = new JWTConfig();
  7. Configuration.GetSection("JWT").Bind(config);
  8. #endregion
  9.  
  10. #region 启用JWT
  11. services.AddAuthentication(Options =>
  12. {
  13. Options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
  14. Options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
  15. }).
  16. AddJwtBearer(options =>
  17. {
  18. options.TokenValidationParameters = new TokenValidationParameters
  19. {
  20. ValidIssuer = config.Issuer,
  21. ValidAudience = config.RefreshTokenAudience,
  22. IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(config.IssuerSigningKey))
  23. };
  24. });
  25. #endregion
  26.  
  27. services.AddMvc().SetCompatibilityVersion(CompatibilityVersion.Version_2_2);
  28. }

注意这里的ValidAudience被赋值为config.RefreshTokenAudience,和FlyLolo.JWT.API中的不一致,用于防止AccessToken和RefreshToken的混用。

再次访问/api/token?code=002&pwd=222222,会返回两个Token:

  1. {"accessToken":{"tokenContent":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8y
    MDA1LzA1L2lkZW50aXR5L2NsYWltcy9uYW1laWRlbnRpZmllciI6IjAwMiIsImh0dHA6Ly9zY2hlbWFzLnhtbHNvYXAub3JnL3dzLzIwMDUvMDUva
    WRlbnRpdHkvY2xhaW1zL25hbWUiOiLmnY7lm5siLCJodHRwOi8vc2NoZW1hcy5taWNyb3NvZnQuY29tL3dzLzIwMDgvMDYvaWRlbnRpdHkvY2xhaW
    1zL3JvbGUiOlsiVGVzdFB1dEJvb2tSb2xlIiwiVGVzdFB1dFN0dWRlbnRSb2xlIl0sIm5iZiI6MTU2NjgwNjQ3OSwiZXhwIjoxNTY2ODA4Mjc5LCJ
    pc3MiOiJGbHlMb2xvIiwiYXVkIjoiVGVzdEF1ZGllbmNlIn0.wlMorS1V0xP0Fb2MDX7jI7zsgZbb2Do3u78BAkIIwGg",
    "expires":"2019-08-26T22:31:19.5312172+08:00"},
  2.  
  3. "refreshToken":{"tokenContent":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJodHRwOi8vc2NoZW1hcy54bWxzb2FwLm9yZy93cy8y
    MDA1LzA1L2lkZW50aXR5L2NsYWltcy9uYW1laWRlbnRpZmllciI6IjAwMiIsImh0dHA6Ly9zY2hlbWFzLnhtbHNvYXAub3JnL3dzLzIwMDUvMDUva
    WRlbnRpdHkvY2xhaW1zL25hbWUiOiLmnY7lm5siLCJodHRwOi8vc2NoZW1hcy5taWNyb3NvZnQuY29tL3dzLzIwMDgvMDYvaWRlbnRpdHkvY2xhaW
    1zL3JvbGUiOlsiVGVzdFB1dEJvb2tSb2xlIiwiVGVzdFB1dFN0dWRlbnRSb2xlIl0sIm5iZiI6MTU2NjgwNjQ3OSwiZXhwIjoxNTY3NDExMjc5LCJ
    pc3MiOiJGbHlMb2xvIiwiYXVkIjoiUmVmcmVzaFRva2VuQXVkaWVuY2UifQ.3EDi6cQBqa39-ywq2EjFGiM8W2KY5l9QAOWaIDi8FnI",
    "expires":"2019-09-02T22:01:19.6143038+08:00"}}

可以使用RefreshToken去请求新的AccessToken

测试用AccessToken可以正常访问FlyLolo.JWT.API,用RefreshToken则不可以。

至此,Token的刷新功能改造完成。代码地址:https://github.com/FlyLolo/JWT.Demo/releases/tag/1.1

疑问:RefreshToken有效期那么长,被盗了怎么办,和直接将AccessToken的有效期延长有什么区别?

个人认为:1. RefreshToken不像AccessToken那样在大多数请求中都被使用。2. 应用类的API较多,对应的服务(器)也可能较多,所以泄露的概率更大一些。

应用JWT进行用户认证及Token的刷新的更多相关文章

  1. ASP.NET Core 2.2 : 二十六. 应用JWT进行用户认证及Token的刷新

    来源:https://www.cnblogs.com/FlyLolo/p/ASPNETCore2_26.html 本文将通过实际的例子来演示如何在ASP.NET Core中应用JWT进行用户认证以及T ...

  2. ASP.NET Core 2.2 : 二十六. 应用JWT进行用户认证

    本文将通过实际的例子来演示如何在ASP.NET Core中应用JWT进行用户认证以及Token的刷新方案(ASP.NET Core 系列目录) 一.什么是JWT? JWT(json web token ...

  3. Node.js 使用JWT进行用户认证

    代码地址如下:http://www.demodashi.com/demo/13847.html 运行环境 该项目基于 node(v7.8.0版本以上) 和 mongodb 数据库,因此电脑上需要安装这 ...

  4. DRF使用JWT进行用户认证

    1. 首先需要安装第三方依赖包 pip install djangorestframework-jwt 2. 在Django的settings文件中 配置全局的JWT认证类 REST_FRAMEWOR ...

  5. 前后端分离下用jwt做用户认证

    0 前后端分离下的用户信息认证 前端使用Vue+axios,后端使用SpringBoot+SpringSecurity. 为了解决http无状态的问题,我采用jwt(json web token)保存 ...

  6. 【laravel】基于jwt实现用户认证

    安装及基础配置 使用 composer 安装 # 建议使用1.0以上版本 composer require tymon/jwt-auth .*@rc 进行一些配置 有些文档会说要添加 Tymon\JW ...

  7. ASP.NET Core 2.2 : 二十七. JWT与用户授权(细化到Action)

    上一章分享了如何在ASP.NET Core中应用JWT进行用户认证以及Token的刷新,本章继续进行下一步,用户授权.涉及到的例子也以上一章的为基础.(ASP.NET Core 系列目录) 一.概述 ...

  8. Laravel 5 中使用 JWT(Json Web Token) 实现基于API的用户认证

    在JavaScript前端技术大行其道的今天,我们通常只需在后台构建API提供给前端调用,并且后端仅仅设计为给前端移动App调用.用户认证是Web应用的重要组成部分,基于API的用户认证有两个最佳解决 ...

  9. 5分钟搞懂:基于token的用户认证

    https://www.qikegu.com/easy-understanding/880 用户认证 用户认证或者说用户登录是确认某人确实是某人的过程,生活中靠身份证,网络上就要靠账号和密码.用户提供 ...

随机推荐

  1. go ---MQTT client

    Paho GO Client   语言 GO 协议 EPL AND EDL 官网地址 http://www.eclipse.org/paho/ API类型 Asynchronous  描述 Paho ...

  2. DNS:从零搭建公司内网DNS服务器

    写在前面的话 网上关于 DNS 的文章其实一搜索一大把,但是看别人的文档一般都会有个问题,乱,不讲究,全是 ctrl c + ctrl v,我个人是看不下去的.头皮发麻.所以决定自己来写写这方面的东西 ...

  3. C语言语法教程-结构体

    2018-09-30 结构体中成员变量地址是连续的,结构体用于描述记录. Create a struct //---------------------------- //struct1.c //创建 ...

  4. C# 随笔写txt

    public static void WriterFile(string file) { string path = AppDomain.CurrentDomain.BaseDirectory; // ...

  5. select into 与 insert into select

    1.select into select into 语句把一个表中的数据插入到另一个表中. 不需要创建临时表,在运行过程中自动创建. 基本语法: select * into #table_Name f ...

  6. JavaScript学习思维导图

    JS基本概念 JS操作符 JS基本语法 JS数组 JS Date用法 JS 字符串用法 JS编程风格 JS实践

  7. 极速体验docker容器健康

    本文目是体验docker容器的健康检查功能,以体验为主不涉及开发,与开发相关的内容会在后面的文章细说. 关于容器健康检查 考虑这样的情况:docker环境中,springboot应用的容器还在,但已无 ...

  8. 微服务架构 ------ 插曲 Mybatis逆向工程

    1.首先是pom.xml, 我们需要引入需要的mvn插件 <?xml version="1.0" encoding="UTF-8"?> <pr ...

  9. Linux操作:使用grep排除搜索的目录

    使用grep时,当一个目录下有一个包含很多文件的目录,但也不想搜索它,怎么办? 使用 --exclude-dir 选项. 单个目录示例: grep -rni 'http' --exclude-dir= ...

  10. 英语chiltonite葡萄石chiltonite单词

    葡萄石Chiltonite 1.葡萄石能够促进血液循环,具有美容养颜的功效,非常适合女性佩戴,可以增加个人魅力,还能加强事业财运,凝聚财富气场. 2.绿色光对应人体心轮,对心脏,肺脏有效用,内涵的磁石 ...