本文我们来探讨下JWT VS Session的问题,我们可直接抛出问题:使用客户端存储的JWT比服务端维持Session更好吗?

既然要比较JWT VS Session,那我们就得知道为何需要JWT和Session,它们共同是为了解决什么问题呢?那我们从一个场景说起,网上购物现已是再平常不过的事情了,当我们将某个商品加入购物车后,然后跳转到其他商品页面此时需要之前选择的商品依然在购物车中,此时就需要维持会话,因为HTTP无状态,所以JWT和Session共同点都是为了持久维持会话而存在,为了克服HTTP无状态的情况,JWT和Session分别是如何处理的呢?

JWT VS Session

Session:当用户在应用系统中登录后,此时服务端会创建一个Session(我们也称作为会话),然后SessionId会保存到用户的Cookie中,只要用户是登录状态,对于每个请求,在Cookie中的SessionId都会发送到服务端,然后服务端会将保存在内存中的SessionId和Cookie中的SessionId进行比较来认证用户的身份并响应。

JWT:当用户在应用系统中登录后,此时服务端会创建一个JWT,并将JWT发送到客户端,客户端存储JWT(一般是在Local Storage中)同时在每个请求头即Authorization中包含JWT,对于每个请求,服务端都会进行验证JWT是否合法,直接在服务端本地进行验证,比如颁发者,受理者等等,以致于无需发出网络请求或与数据库交互,这种方式可能比使用Session更快,从而加快响应性能,降低服务器和数据库服务器负载。

通过如上对JWT认证和Session认证简短的描述,我们知道二者最大的不同在于Session是存储在服务端,而JWT存储在客户端。服务端存储会话无外乎两种,一种是将会话标识符存储在数据库,一种是存储在内存中维持会话,我想大多数情况下都是基于内存来维持会话,但是这会带来一定的问题,如果系统存在大流量,也就是说若有大量用户访问系统,此时使用基于内存维持的会话则限制了水平扩展,但对基于Token的认证则不存在这样的问题,同时Cookie一般也只适用于单域或子域,如果对于跨域,假如是第三方Cookie,浏览器可能会禁用Cookie,所以也受浏览器限制,但对Token认证来说不是问题,因为其保存在请求头中。

如果我们将会话转移到客户端,也就是说使用Token认证,此时将解除会话对服务端的依赖,同时也可水平扩展,不受浏览器限制,但是与此同时也会带来一定的问题,一是令牌的传输安全性,对于令牌传输安全性我们可使用HTTPS加密通道来解决,二是与存储在Cookie中的SessionId相比,JWT显然要大很多,因为JWT中还包含用户信息,所以为了解决这个问题,我们尽量确保JWT中只包含必要的信息(大多数情况下只包含sub以及其他重要信息),对于敏感信息我们也应该省略掉从而防止XSS攻击。JWT的核心在于声明,声明在JWT中是JSON数据,也就是说我们可以在JWT中嵌入用户信息,从而减少数据库负载。所以综上所述JWT解决了其他会话存在的问题或缺点:

更灵活、更安全、减少数据库往返,从而实现水平可伸缩、防篡改客户端声明、移动设备上能更好工作、适用于阻止Cookie的用户

综上关于JWT在有效期内没有强制使其无效的能力而完全否定JWT的好处显然站不住脚,当然不可辩驳的是若是没有如上诸多使用限制,实现其他类型的身份验证完全也是合情合理且合法的,需综合权衡,而非一家之言下死结论。到目前为止,我们一直讨论的是JWT VS Session认证,而不是JWT VS Cookie认证,但是如标题我们将Cookie也纳入了,只是想让学习者别搞混了,因为JWT VS Cookie认证这种说法是错误的,Cookie只是一种存储和传输信息介质,只能说我们可以通过Cookie存储和传输JWT。接下来我们来实现Cookie存储和传输JWT令牌。

JWT AS Cookies Identity Claim

在Startup中我们可以添加如下Cookie认证中间件,此时我们有必要了解下配置Cookie的一些选项,通过对这些选项的配置来告知Cookie身份认证中间件在浏览器中的表现形式,我们看下几个涉及到安全的选项。

配置HttpOnly标志着Cookie是否仅供服务端使用,而不能通过前端直接访问。

配置SecurePolicy将限制Cookie为HTTPS,在生产环境建议配置此参数同时支持HTTPS。

配置SameSite用来指示浏览器是否可以将Cookie与跨站点请求一同使用,若是对于OAuth身份认证,可设置为Lax,允许外部链接重定向发出比如POST请求而维持会话,若是Cookie认证,设置为Restrict,因为Cookie认证只适用于单站点,若是设置为None,则不会设置Cookie Header值。(注意:SameSite属性在谷歌、火狐浏览器均已实现,对于IE11好像不支持,Safari从版本12.1开始支持该属性)

在创建.NET Core默认Web应用程序时,在ConfigureServices方法中,通过中间件直接配置了全局Cookie策略,如下:

当然默认配置了全局Cookie策略,同时也在Configure方法中使用其策略如下:

我们也可以直接在上述调用使用Cookie策略中间件的方法中来设置对应参数策略,如下:

若是我们在添加Cookie中间件的同时也配置全局Cookie策略,我们会发现对于属性HTTPOnly和SameSite都可配置,此时个人猜测会存在覆盖的情况,如下:

对于需要认证的控制器我们需要添加上[Authroize]特性,对每一个控制器我们都得添加这样一个特性,相信大部分童鞋都是这么干的。其实我们大可反向操作,对于无需认证的我们添加可匿名访问特性即可,而需要认证的控制器我们进行全局配置认证过滤器,如下:

好了到了这里,我们只是粗略的讲解了下关于Cookie中间件参数配置和Cookie全局配置策略的说明,没有太深入去研究里面的细枝末节,等遇到问题再具体分析吧。继续回到话题,Cookie认证相比JWT对API访问来讲安全系数低,所以我们完全可以在Cookie认证中结合JWT来使用。具体我们可尝试怎么搞呢?将其放到身份信息声明中,我想应该是可行的方式,我们来模拟登陆和登出试试,大概代码如下:

上述代码很简单,无需我再多讲,和Cookie认证无异,只是我们在声明中添加了access_token来提高安全性,接下来我们自定义一个Action过滤器特性,并将此特性应用于Action方法,如下:

JWT Combine Cookie Authentication

如上是采用将JWT放到声明的做法,我想这么做也未尝不可,至少我没找到这么做有什么不妥当的地方。我们也可以将Cookie认证和JWT认证进行混合使用,只不过是在上一节的基础上添加了Cookie中间件罢了,如下图:

通过如上配置后我们就可以将Cookie和JWT认证来组合使用了,比如我们在用户登录后,如下图点击登录后显示当前登录用户名,然后点击退出,在退出Action方法上我们添加组合特性:

在上一节中,我们通过获取AccessToken,从而访问端口号为5001的客户端来获取当前时间,那现在我们针对获取当前时间的方法添加上需要Cookie认证,如下:

Cookie认证撤销

在.NET Core 2.1版本通过Cookie进行认证中,当用户与应用程序进行交互修改了信息,需要在cookie的整个生命周期,也就说在注销或cookie过期之前看不到信息的更改时,我们可通过cookie的身份认证事件【撤销身份】来实现这样的需求,下面我们来看看。

我们通过重写CookieAuthenticationEvents事件中的ValidatePrincipal,然后判断写在内存中关于用户表示是否存在,若存在则调用 context.RejectPrincipal() 撤销用户身份。然后我们在添加Cookie中间件里配置该事件类型以及对其进行注册:

接下来我们写一个在页面上点击【修改信息】的方法,并在内存中设置撤销指定用户,如下:

从如上动图中我们可以看到,当点击修改信息后,然后将撤销的用户标识写入到内存中,然后跳转到Index页面,此时调用我们写的撤销事件,最终重定向到登录页,且此时用户cookie仍未过期,所以我们能够在左上角看到用户名,不清楚这种场景在什么情况下才会用到。

跳转至登录携带或移除参数

当我们在某个页面进行操作时,若此时Token或Cookie过期了,此时则会自动引导用户且将用户当前访问的URL携带并重定向跳转到登录页进行登录,比如关于博客园如下跳转URL:

但是如果我们有这样的业务场景:用于跳转至登录页时,在URL上需要携带额外的参数,我们需要获取此业务参数才能进行对应业务处理,那么此时我们应该如何做呢?我们依然是重写CookieAuthenticationEvents事件中的RedrectToLogin方法,如下:

这里需要注意的是因为上述我们用到了IActionContextAccessor,所以我们需要将其进行对应如下注册:

最终我们跳转到登录页将会看到我们添加的额外参数id也将呈现在url上,如下:

本节我们讲解了Session和JWT的优缺点以及Cookie认证中可能我们需要用到的地方,下一节也是JWT最后一节内容,我们讲讲并探讨如何实现刷新Token,感谢阅读

ASP.NET Core Web Api之JWT VS Session VS Cookie(二)相关推荐

  1. ASP.NET Core Web Api之JWT(一)

    最近沉寂了一段,主要是上半年相当于休息和调整了一段时间,接下来我将开始陆续学习一些新的技能,比如Docker.Jenkins等,都会以生活实例从零开始讲解起,到时一并和大家分享和交流.接下来几节课的内 ...

  2. ASP.NET Core Web API/MVC应用中间件中的Cookie记录

    目录 介绍 背景 Cookie身份验证事件 Cookie记录中间件 预防措施 结论 介绍 有时,我们必须在开发站点或生产站点中登录Cookie以进行调试.我们有过这样的情况. 背景 在我们为Andro ...

  3. ASP.NET Core Web Api之JWT刷新Token(三)

    本节我们进入JWT最后一节内容,JWT本质上就是从身份认证服务器获取访问令牌,继而对于用户后续可访问受保护资源,但是关键问题是:访问令牌的生命周期到底设置成多久呢? 见过一些使用JWT的童鞋会将JWT ...

  4. 用JWT来保护我们的ASP.NET Core Web API

    在用Middleware给ASP.NET Core Web API添加自己的授权验证 中,自己动手写了一个Middleware来处理API的授权验证,现在就采用另外一种方式来处理这个授权验证的问题,毕 ...

  5. 【壹刊】Azure AD 保护的 ASP.NET Core Web API (下)

    一,引言 上一节讲到如何在我们的项目中集成Azure AD 保护我们的API资源,以及在项目中集成Swagger,并且如何把Swagger作为一个客户端进行认证和授权去访问我们的WebApi资源的?本 ...

  6. 如何测试ASP.NET Core Web API

    在本文中,我们将研究如何测试你的ASP .NET Core 2.0 Web API解决方案.我们将了解使用单元测试进行内部测试,使用全新的ASP .NET Core的集成测试框架来进行外部测试. 本文 ...

  7. 针对ASP.NET Core Web API的先进架构

    \ 本点要点 \\ 与传统的ASP.NET相比,ASP.NET Core的新架构提供了一些好处\\t ASP.NET Core从一开始就包含对依赖注入的支持\\t 单一职责原则简化了实施和设计.\\t ...

  8. ASP.NET Core Web APi获取原始请求内容

    前言 我们讲过ASP.NET Core Web APi路由绑定,本节我们来讲讲如何获取客户端请求过来的内容. ASP.NET Core Web APi捕获Request.Body内容 [HttpPos ...

  9. 重温.NET下Assembly的加载过程 ASP.NET Core Web API下事件驱动型架构的实现(三):基于RabbitMQ的事件总线...

    重温.NET下Assembly的加载过程 最近在工作中牵涉到了.NET下的一个古老的问题:Assembly的加载过程.虽然网上有很多文章介绍这部分内容,很多文章也是很久以前就已经出现了,但阅读之后发现 ...

最新文章

  1. 主席树 | 莫队 ---- Codeforces Round #716 (Div. 2) D. Cut and Stick [主席树or莫队优化] 区间众数问题(静态)
  2. 计算机网络技能专项训练一:基础配置
  3. 「我要出轨了」!伯克利的这个AI,可以预测机器人何时将脱离
  4. 案例驱动python编程入门-python实现事件驱动
  5. 十九、二叉树的最近的公共祖先
  6. 区别不同浏览器,CSS hack写法
  7. java源码编译_java 源码编译
  8. win7美化_Win10桌面美化实用软件推荐
  9. Mirth连接Sybase数据库
  10. 服务器打印后台程序没有响应,Win10提示打印后台处理程序服务没有运行如何解决...
  11. 如何使用Apollo / Graphene管理GraphQL突变中的文件上传
  12. 风入松——北大校园的风入松书店不知何处去
  13. android app套壳马甲开发,Android应用开发最佳实践:马甲包配置管理
  14. 2021-10-28项目集管理PgMP:刷新项目管理思维与架构︱项目管理者联盟联合创始人宣晓锋
  15. 寒江独钓 第二章 课后习题
  16. openstack 中ovs-vlan 转换
  17. php使用addons,think addons教程
  18. tomcat端口修改
  19. 5款国产ARM芯片替代ST
  20. [转]UML八大误解

热门文章

  1. 3d镜头 适配_您是否应该将镜头适配器与无反光镜相机一起使用?
  2. 将不确定变为确定~老赵写的CodeTimer是代码性能测试的利器
  3. 为VMware虚拟主机添加新磁盘
  4. .net core入门之web应用
  5. 深度分析 Java 的 ClassLoader 机制(源码级别)(转)
  6. eclipse 运行MapReduce程序错误异常汇总(解决Map not fount)
  7. XP下Virtualbox虚拟Ubuntu共享文件夹
  8. RTC 媒体流数据包丢包问题解决
  9. Oracle结构设计技巧(访问数据库象访问内存一样 快)
  10. 堪比JMeter的.Net压测工具 - Crank 入门篇