CXYVIP官网源码交易平台_网站源码_商城源码_小程序源码平台-丞旭猿论坛
CXYVIP官网源码交易平台_网站源码_商城源码_小程序源码平台-丞旭猿论坛
CXYVIP官网源码交易平台_网站源码_商城源码_小程序源码平台-丞旭猿论坛

从0开始构建你的API网关——API网关的职责和相关的技术原理

传统的Cookie和Session认证在了解了API网关身份认证的职责之后,下面介绍一些常用的认证方式,最常用也是最经典的认证方式是Cookie和SessionCookie是客户端用于存储数据的小型文件,客户端存储Cookie的方式又分为内存存储和硬盘存储。

内存中的Cookie会在浏览器关闭时丢失,而硬盘中的Cookie可以长期保存,我们也可以设置Cookie的过期时间或在客户端手动清除CookieCookie保存在客户端本地,但会自动附加在每个HTTP的请求中,服务端可以通过HTTP的请求获取Cookie的信息,这是因为HTTP本身无状态。

服务器不知道用户之前的行为或者当前的状态,严重阻碍了客户端与服务端的交互,很多购物网站、搜索引擎、视频网站等都常用Cookie来记录用户的行为,从而通过分析Cookie的数据,对用户进行一些精准的广告或内容推送。

Session与Cookie恰好相反,Session是保存在服务端的数据,是Servlet提供的一种跨页面识别用户请求和存储用户信息的方式,通常Session会将数据存储在内存中,由于HTTP的无状态性,服务端会认为每次请求都是一个新的请求。

就算有了Cookie技术,多次请求之间仍然独立,所以服务端需要一种方式能够识别多次请求的用户,从而可以跟踪用户的使用信息,与用户建立一个会话机制,无论用户发送多少次请求,访问多少个页面,服务端始终能够知道这些请求是在同一次会话中和同一个用户发生的交互,而不用反复去识别用户的信息,当然,这需要和Cookie一起配合来使用,客户端与服务端建立Session的示意图如图5.16所示。

用户在第一次请求服务端时,服务端会创建一个Session,并分配唯一的Session ID作为客户端的Cookie,客户端会将Session ID的Cookie存储于内存中,并在后续的请求中附带这个Cookie,服务端通过获取Cookie的值就可以识别当前请求的用户身份。

当然,Session有时效性,通常默认为30分钟,而且由于存储Session ID的Cookie是使用存储的方式存储在客户端,当浏览器关闭时,即使服务端的Session没有销毁,但客户端的Session ID已经丢失,这时再次请求服务端,服务端会认为这是一次新的请求,就会创建一个新的会话。

这里的客户端通常是我们系统的前端,如浏览移动端App等,而服务端在微服务架构中通常是指API网关在明白了Cookie和Session的作用后,如何利用Cookie和Session的机制实现用户的身份认证?其实做法和图5.16中的流程类似,既然可以使用Session ID作为用户的唯一标识,那么就可以使用Session来存储用户的信息,如登录状态、用户基础信息等,然后通过识别请求中Cookie的Session ID来判断用户的登录状态和获取用户的基本信息。

在图5.17中,通过Cookie和Session来实现一个简单的用户名密码登录

由图5.17可知,用户通过浏览器发起登录请求到API网关,由API网关负责用户登录认证的相关操作,首先API网关会调用用户服务查询用户的信息,然后进行用户名密码的校验,若校验成功则更新用户的状态,并将一些基础的用户信息保存到Session中。

如果用户是首次访问系统,此时API网关会创建一个新的Session,若不是,则执行更新Session的操作,然后API网关会在返回登录结果的同时,在响应头中附带Session ID的信息,浏览器将Session ID保存到内存的Cookie中,以便在下次请求时来标识自己的会话ID,从而不需要反复登录,如图5.18所示。

由图5.18可知,当用户已经成功登录后,再次请求服务时,API网关会首先校验请求中的Session ID是否为真实存在于Session中的ID我们在登录时已将用户信息保存在Session中,因此API网关会通过Session获取到用户的基本信息及登录状态,如果状态是已登录,就不会对请求进行拦截,直接转发请求到后端的服务,然后将数据返回给浏览器。

这样就实现了使用Cookie和Session的方式将用户状态保存在API网关中,只要Session没有失效,用户的登录状态就不会失效当然,这种方式存在一定问题,它使我们的API网关从无状态变成有状态,一旦服务拥有了状态,就需要考虑在分布式系统中如何保证这些状态的一致性,即需要有一定的机制来同步多实例下的状态。

为什么要这样做?在生产环境中将API网关部署了两个实例(A和B),前端通过一定的方式进行负载均衡,如Nginx,这时一个用户在API网关A中登录,它会将用户的状态保存在自己的Session中,下次请求如果被分配到了API网关B,那么在API网关B中并没有保存用户的状态,就会认为用户没有登录过,请求会被拦截。

我们的Session保存在内存中,所以哪怕不是在分布式的环境下,单实例的服务一旦更新或重启,所有的用户状态都将丢失因此,只要API网关发布了任何一个版本更新,所有的用户都需要重新登录,这样显然无法接受所以,我们需要解决两个问题:一是Session需要在多节点之间保持同步;二是Session需要一定程度的持久化存储。

笔者参与过的分布式项目中有很多解决方案,如使用Memcached、Ehcache内存框架做Session的存储,然后在服务端集成消息队列,通过消息订阅的方式在多个服务实例中进行Session的传播,从而保证Session的同步,或者使用关系型数据库,如将Session持久化到MySQL中,然后每次通过MySQL进行Session的存取,多个实例均访问一个数据库即可,这些方式在当时都能解决项目中遇到的问题。

但这些方式也具有一定的缺陷或局限性,首先,消息队列的方式增加了系统的复杂度,每次认证都需要额外收发消息的开销,而且消息队列本身的异步设计也使多节点之间无法做到完全实时的状态一致使用数据库作为统一的Session存储服务的思路很好,但关系型数据库本身的读写性能和并发能力无法很好地支撑一些高并发场景。

那么是否还有更好的方式呢?之前说过集中式的外部存储Session是很好的思路,但需要读写性能很高、并发能力很强的存储服务支撑,所以通常会使用Redis来做Session的存储Redis是一个开源的内存结构的NoSQL数据库,通常会用作数据库、缓存和消息代理等,它支持多种数据结构,支持数据持久化和集群部署,总之它是一个读写性能快、并发能力强的存储数据库。

因此,我们可以在API网关中集成Redis作为Session的外部存储设备,如图5.19所示。

由图5.19可知,使用Cookie和Session来实现用户认证的逻辑一样,只是在服务端,也就是API网关集成Redis服务,Session不再存储在服务本地进程的内存中,而是集中存储在Redis当客户端再次发送带有Session ID的请求时,API网关会在Redis中查找对应的Session,不需要担心Session的同步问题。

同时,Redis中可以设置数据的过期时间,也可以设置Session的存在时间,并且只要Session没有超时,就算服务全部重启,用户的状态依然保留当然,在图5.7中,认证可以单独封装成一个认证服务,这样API网关依然可以无状态。

认证服务用来集成Redis并管理用户的会话状态,如图5.20所示

图5.20 认证服务集成Redis这样,API网关本身就可以和认证规则、Redis、状态管理等逻辑解耦当然,并不是分离就是好的,还需要先分析系统的实际需求场景和现状,再来考虑项目架构的优化和重构基于JSON的令牌JWT。

在使用Cookie和Session完成用户的身份认证之后,这里再介绍一种新的认证方式:JWT(JSON Web Tokens),这是一种基于JSON的网络令牌的开放标准。

JWT定义了一种紧凑且独立的方式,可以在客户端和服务端之间以JSON对象安全地传输信息,JWT可以使用HMAC加密算法或使用RSA或ECDSA的公钥/私钥对信息进行签名加密,信息可以通过数字签名进行验证和信任。

例如,用户登录后,服务端会生成JWT的信息返回给客户端,然后客户端会存储JWT,并在之后的每个请求头中都附带JWT的信息,服务端通过一定的方式验证令牌的真伪识别用户身份,如图5.21所示由图5.21可知,服务端将不再保存用户状态,所有的数据都被按照JWT的标准加密成令牌信息,并由客户端自行保存,只需每次请求时附带令牌,服务器校验令牌的有效性即可,只要是校验成功的令牌就会完全地信任身份,服务端不需要关心状态的一致性,也不需要做任何的用户信息的持久化操作,所有的信息都可以通过令牌来获取。

以JWT作为身份认证方式在SSO(Single Sign On,单点登录)中尤为常见,因为它完全解放了服务端到端的复杂逻辑,无论后端架构是不是集群,请求是否跨越,只要令牌能够校验有效,就证明是其合法用户。

除了身份认证,JWT还常常用于信息交换,是在各方之间安全传输信息的较好方法因为JWT可以签名,所以我们可以确定信息的发件人是否符合真实身份此外,由于使用了标头和有效负载来计算签名,我们还可以验证信息的内容是否被篡改,因此JWT技术的安全性很高。

那么JWT到底怎么样?又是如何做到签名和加密验证的?JWT的数据是由3个部分组成的,其数据样例如图5.22所示。

在图5.22中,JWT的3个部分数据都是由base64加密而成的,并且使用字符“”分隔开,3个部分分别表示消息头(Header)、消息体(Payload,又称负载)和签名(Signature),即JWT的内容如下。

其中,消息头的明文内容如下。

alg是算法Algorithm的英文缩写,表示JWT签名的加密算法类型,typ是令牌类型Token Type的英文缩写,表示令牌的类型。消息体的明文就是JWT原始的消息内容,使用JSON格式,例如:

签名是JWT的关键,包括了消息头和消息体以及加密密钥的加密结果 。 例如,我们的alg是 HS256,就代表使用的加密算法是HMACSHA256,其签名的内容如下。

在图5.21中,服务端通常会按照上面的方式创建JWT,然后将JWT发给客户端,客户端会自己存储JWT,如存储在Local Storage中,然后在每次请求服务端时会将JWT的消息附带在请求中,通常是放在HTTP的消息头中。

当服务端得到JWT消息之后,就会使用JWT中的消息头和消息体以及密钥(加密签名所使用的密钥保存在服务端)再次计算出签名,和JWT中的签名相比较就可以判断该JWT是否有效与Cookie和Session相比,JWT的身份认证方式确实有些优点:服务端可以是无状态的,不用考虑Session的一致性或引入的外部组件来存储Session;不依赖Cookie,这样不支持Cookie的浏览器也可以使用,并且兼容性更好;跨域信息传递更方便等。

但是,JWT同样有很多不如Cookie+Session实现身份认证的地方,如每次请求头中都要附带JWT,相比Session ID,使用JWT要花费更多的流量,在客户端也需要占用更多的空间,而且将用户数据保存在客户端也会有一定的安全隐患,尤其在使用Local Storage存储时容易受到XSS(Cross Site Script,跨站脚本)攻击,需要前端考虑更多的安全问题。

所以,JWT并不是绝对的比Cookie+Session的身份认证方式更好,我们在选择方案时要根据实际的项目需求和场景来考虑当然,现在很多框架都能够帮我们做到Session的管理,如使用Spring Session Data Redis几乎不需要写任何代码就可以集成Redis来管理Session,Cookie+Session的缺点也正在被框架所减弱,所以出于更安全的考虑,一般会推荐项目使用Cookie+Session的方式来实现身份认证。

以上是关于API网关的概念、职责和相关的技术原理,下面具体介绍API网关的相关技术和用法本文给大家讲解的内容是传统的Cookie和Session认证下篇文章给大家讲解的是API网关技术实战;觉得文章不错的朋友可以转发此文关注小编;。

感谢大家的支持!

© 版权声明
THE END
喜欢就支持一下吧
点赞0赞赏 分享
相关推荐
评论 抢沙发
头像
欢迎您留下宝贵的见解!
提交
头像

昵称

取消
昵称表情代码图片

    暂无评论内容