实践剖析.NET Core 如何支持 Cookie 滑动过期和 JWT 混合认证、授权

2025-05-29 0 27

实践剖析.NET Core 如何支持 Cookie 滑动过期和 JWT 混合认证、授权

首先我们实现Cookie认证,然后再次引入JWT,最后在结合二者使用时联系其他我们可能需要注意的事项

Cookie认证

在startup中我们添加cookie认证服务,如下:

  1. services.AddAuthentication(options=>
  2. {
  3. options.DefaultAuthenticateScheme=CookieAuthenticationDefaults.AuthenticationScheme;
  4. options.DefaultChallengeScheme=CookieAuthenticationDefaults.AuthenticationScheme;
  5. })
  6. .AddCookie(options=>
  7. {
  8. options.ExpireTimeSpan=TimeSpan.FromMinutes(1);
  9. options.Cookie.Name="user-session";
  10. options.SlidingExpiration=true;
  11. });

接下来则是使用认证和授权中间件,注意将其置于路由和终结点终结点之间,否则启动也会有明确异常提示

  1. app.UseRouting();
  2. app.UseAuthentication();
  3. app.UseAuthorization();
  4. app.UseEndpoints(endpoints=>
  5. {
  6. ……
  7. });

我们给出测试视图页,并要求认证即控制器添加特性

  1. [Authorize]
  2. publicclassHomeController:Controller
  3. {
  4. publicIActionResultIndex()
  5. {
  6. returnView();
  7. }
  8. }

当进入首页,未认证默认进入account/login,那么接下来创建该视图

  1. publicclassAccountController:Controller
  2. {
  3. [AllowAnonymous]
  4. publicIActionResultLogin()
  5. {
  6. returnView();
  7. }
  8. ……
  9. }

我们启动程序先看看效果

实践剖析.NET Core 如何支持 Cookie 滑动过期和 JWT 混合认证、授权

如上图,自动跳转至登录页,此时我们点击模拟登录按钮,发起请求去模拟登录(发起ajax请求代码就占不用篇幅给出了)

  1. ///<summary>
  2. ///模拟登录
  3. ///</summary>
  4. ///<returns></returns>
  5. [HttpPost]
  6. [AllowAnonymous]
  7. publicasyncTask<IActionResult>TestLogin()
  8. {
  9. varclaims=newClaim[]
  10. {
  11. newClaim(ClaimTypes.Name,"Jeffcky"),
  12. };
  13. varclaimsIdentity=newClaimsIdentity(claims,"Login");
  14. awaitHttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme,newClaimsPrincipal(claimsIdentity));
  15. returnOk();
  16. }

上述无非就是构建身份以及该身份下所具有的身份属性,类似个人身份证唯一标识个人,身份证上各个信息即表示如上声明

同时呢,肯定要调用上下文去登录,在整个会话未过期之前,根据认证方案获取对应处理方式,最后将相关信息进行存储等等,有兴趣的童鞋可以去了解其实现细节哈

实践剖析.NET Core 如何支持 Cookie 滑动过期和 JWT 混合认证、授权

当我们请求过后,再次访问首页,将看到生成当前会话信息,同时我们将会话过期设置为1分钟,在1分钟内未进行会话,将自动重定向至登录页

注意如上标注并没有值,那么这个值可以设置吗?当然可以,在开始配置时我们并未给出,那么这个属性又代表什么含义呢?

  1. options.Cookie.MaxAge=TimeSpan.FromMinutes(2);

那么结合ExpireTimeSpan和MaxAge使用,到底代表什么意思呢?我们暂且撇开滑动过期设置

ExpireTimeSpan表示用户身份认证票据的生命周期,它是认证cookie的有效负载,存储的cookie值是一段加密字符串,在每次请求时,web应用程序都会根据请求对其进行解密

MaxAge控制着cookie的生命周期,若cookie过期,浏览器将会自动清除,如果没有设置该值,实质上它的生命周期就是ExpireTimeSpan,那么它到底有何意义呢?

上述我们设置票据的生命周期为1分钟,同时我们控制cookie的生命周期为2分钟,若在2分钟内关闭浏览器或重启web应用程序,此时cookie生命周期并未过期,所以仍将处于会话状态即无需登录,若未设置MaxAge,关闭浏览器或重启后将自动清除其值即需登录,当然一切前提是未手动清除浏览器cookie

问题又来了,在配置cookie选项中,还有一个也可以设置过期的属性

  1. options.Cookie.Expiration=TimeSpan.FromMinutes(3);

当配置ExpireTimeSpan或同时配置MaxAge时,无需设置Expiration,因为会抛出异常

实践剖析.NET Core 如何支持 Cookie 滑动过期和 JWT 混合认证、授权

JWT认证

上述已经实现Cookie认证,那么在与第三方进行对接时,我们要使用JWT认证,我们又该如何处理呢?

首先我们添加JWT认证服务

  1. .AddJwtBearer(options=>
  2. {
  3. options.TokenValidationParameters=newTokenValidationParameters
  4. {
  5. ValidateIssuerSigningKey=true,
  6. IssuerSigningKey=newSymmetricSecurityKey(Encoding.UTF8.GetBytes("1234567890123456")),
  7. ValidateIssuer=true,
  8. ValidIssuer="http://localhost:5000",
  9. ValidateAudience=true,
  10. ValidAudience="http://localhost:5001",
  11. ValidateLifetime=true,
  12. ClockSkew=TimeSpan.FromMinutes(5)
  13. };
  14. });

JWT Token置于cookie中,此前文章已有讲解,这里我们直接给出代码,先生成Token

  1. privatestringGenerateToken(Claim[]claims)
  2. {
  3. varkey=newSymmetricSecurityKey(Encoding.UTF8.GetBytes("1234567890123456"));
  4. vartoken=newJwtSecurityToken(
  5. issuer:"http://localhost:5000",
  6. audience:"http://localhost:5001",
  7. claims:claims,
  8. notBefore:DateTime.Now,
  9. expires:DateTime.Now.AddMinutes(5),
  10. signingCredentials:newSigningCredentials(key,SecurityAlgorithms.HmacSha256)
  11. );
  12. returnnewJwtSecurityTokenHandler().WriteToken(token);
  13. }

在登录方法中,将其写入响应cookie中,如下这般

  1. ///<summary>
  2. ///模拟登录
  3. ///</summary>
  4. ///<returns></returns>
  5. [HttpPost]
  6. [AllowAnonymous]
  7. publicasyncTask<IActionResult>TestLogin()
  8. {
  9. varclaims=newClaim[]
  10. {
  11. newClaim(ClaimTypes.Name,"Jeffcky"),
  12. };
  13. varclaimsIdentity=newClaimsIdentity(claims,"Login");
  14. Response.Cookies.Append("x-access-token",GenerateToken(claims),
  15. newCookieOptions()
  16. {
  17. Path="/",
  18. HttpOnly=true
  19. });
  20. awaitHttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme,newClaimsPrincipal(claimsIdentity));
  21. returnOk();
  22. }

去取Bearer Token值,若成功取到这赋值给如下context.Token,所以此时我们需要手动从cookie中取出token并赋值

  1. options.Events=newJwtBearerEvents
  2. {
  3. OnMessageReceived=context=>
  4. {
  5. varaccessToken=context.Request.Cookies["x-access-token"];
  6. if(!string.IsNullOrEmpty(accessToken))
  7. {
  8. context.Token=accessToken;
  9. }
  10. returnTask.CompletedTask;
  11. }
  12. };

一切已就绪,接下来我们写个api接口测试验证看看

  1. [Authorize("Bearer")]
  2. [Route("api/[controller]/[action]")]
  3. [ApiController]
  4. publicclassJwtController:ControllerBase
  5. {
  6. [HttpGet]
  7. publicIActionResultTest()
  8. {
  9. returnOk("testjwt");
  10. }
  11. }

思考一下,我们通过Postman模拟测试,会返回401吗?结果会是怎样的呢?

实践剖析.NET Core 如何支持 Cookie 滑动过期和 JWT 混合认证、授权

问题不大,主要在于该特性参数为声明指定策略,但我们需要指定认证方案即scheme,修改成如下:

实践剖析.NET Core 如何支持 Cookie 滑动过期和 JWT 混合认证、授权

如此在与第三方对接时,请求返回token,后续将token置于请求头中即可验证通过,同时上述取cookie中token并手动赋值,对于对接第三方则是多余,不过是为了诸多其他原因而已

  1. [Authorize(AuthenticationSchemes="Bearer,Cookies")]

注意混合认证方案设置存在顺序,后者将覆盖前者即如上设置,此时将走cookie认证

实践剖析.NET Core 如何支持 Cookie 滑动过期和 JWT 混合认证、授权

滑动过期思考扩展

若我们实现基于Cookie滑动过期,同时使用signalr进行数据推送,势必存在问题,因为会一直刷新会话,那么将导致会话永不过期问题,从安全层面角度考虑,我们该如何处理呢?

我们知道票据生命周期存储在上下文AuthenticationProperties属性中,所以在配置Cookie选项事件中我们可以进行自定义处理

  1. publicclassCookieAuthenticationEventsExetensions:CookieAuthenticationEvents
  2. {
  3. privateconststringTicketIssuedTicks=nameof(TicketIssuedTicks);
  4. publicoverrideasyncTaskSigningIn(CookieSigningInContextcontext)
  5. {
  6. context.Properties.SetString(
  7. TicketIssuedTicks,
  8. DateTimeOffset.UtcNow.Ticks.ToString());
  9. awaitbase.SigningIn(context);
  10. }
  11. publicoverrideasyncTaskValidatePrincipal(
  12. CookieValidatePrincipalContextcontext)
  13. {
  14. varticketIssuedTicksValue=context
  15. .Properties.GetString(TicketIssuedTicks);
  16. if(ticketIssuedTicksValueisnull||
  17. !long.TryParse(ticketIssuedTicksValue,outvarticketIssuedTicks))
  18. {
  19. awaitRejectPrincipalAsync(context);
  20. return;
  21. }
  22. varticketIssuedUtc=
  23. newDateTimeOffset(ticketIssuedTicks,TimeSpan.FromHours(0));
  24. if(DateTimeOffset.UtcNow-ticketIssuedUtc>TimeSpan.FromDays(3))
  25. {
  26. awaitRejectPrincipalAsync(context);
  27. return;
  28. }
  29. awaitbase.ValidatePrincipal(context);
  30. }
  31. privatestaticasyncTaskRejectPrincipalAsync(
  32. CookieValidatePrincipalContextcontext)
  33. {
  34. context.RejectPrincipal();
  35. awaitcontext.HttpContext.SignOutAsync();
  36. }
  37. }

在添加Cookie服务时,有对应事件选项,使用如下

  1. options.EventsType=typeof(CookieAuthenticationEventsExetensions);

扩展事件实现表示在第一次会话到当前时间截止超过3天,则自动重定向至登录页,最后将上述扩展事件进行注册即可

原文链接:https://mp.weixin.qq.com/s/zff_H_7eG0EaV7dP5xoMhg

收藏 (0) 打赏

感谢您的支持,我会继续努力的!

打开微信/支付宝扫一扫,即可进行扫码打赏哦,分享从这里开始,精彩与您同在
点赞 (0)

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。

快网idc优惠网 建站教程 实践剖析.NET Core 如何支持 Cookie 滑动过期和 JWT 混合认证、授权 https://www.kuaiidc.com/97018.html

相关文章

发表评论
暂无评论