分布式session管理解决方案

一、传统系统session管理方案

1.利用cookie存放

将Session对象保存在Cookie,然后存放在浏览器端。每次浏览器向服务器发送请求的时候,都会把整个Session对象放在请求里一起发送到服务器,以此来实现Session共享。这样的方案实现起来特别方便,但是由于Cookie的存储容量比较小,所以这个方案只适用于Session数据量小的场景。

2.Session复制

官方文档:Clustering/Session Replication How-To

部分应用服务器能够支持Session复制功能,例如Tomcat。用户可以通过修改配置文件,让应用服务器进行Session复制,保持每一个服务节点的Session数据达到一致。但是这个方案的实现依赖于应用服务器。当应用被大量用户访问时,每个服务器都需要有一部分内存用来存放Session,同时因为大量Session通过网路传输进行复制,将会占用网络资源,还可能因为网络延迟导致程序异常。

3.Session粘滞

利用负载均衡器的分发能力,将同一浏览器上同一用户的请求,都定向发送到固定服务器上,让这个服务器处理该用户的所有请求,这样只要这个服务器上保存了用户Session,就能保证用户的状态一致性。但是这个方案依赖于负载均衡器,而且只适用于横向扩展的集群场景,不能满足分布式场景。

二、分布式系统session集中管理方案

分布式系统中,我们会将session集中存储,比如存储到redis中。这种方案比较常见的实现方式就是RedisSessionManager和Spring-Session。

1.RedisSessionManager 

官网:tomcat-redis-session-manager

测试实验:使用tomcat-redis-session-manager实现session共享

tomcat-redis-session-manager是一个基于Redis和Tomcat实现Session集中管理的开源方案。通过扩展Tomcat的SessionManager,并且在配置文件中替换Tomcat默认的SessionManager来实现Session管理。虽然实现起来比较简单,但是与Tomcat耦合,不适用于其他Web服务器。

2.Spring-Session

官方文档:Spring-Session

Spring Session是Spring提供的一套Session管理方案,通过一个SessionFilter将所有访问应用的请求都拦截下来,然后使用Request包装类接管Session管理。SpringSession不与应用服务器耦合,能适用于常规服务器。同时还提供了在浏览器下对同一应用存储多个Session等功能。

3.基于Spring-Session改造实现

SpringSession优点颇多,所以开始的时候我们曾尝试将SpringSession集成到公司产品中来进行Session集中管理,但在集成过程中考虑到以下几点,最终放弃了集成。

  • SpringSession功能丰富,但我们并不是都需要。
  • SpringSession的实现代码量较多,还需要配合Spring-data-redis进行使用。
  • 如果后续要对Session管理的代码进行修改维护,需要把SpringSession的代码都梳理一遍,学习维护成本比较高。

所以最终我们决定使用Redis作为Session的存储介质,然后参考SpringSession的实现理念,自己设计开发一套轻量级的Session集中管理实现。

同样使用SessionFilter进行用户请求拦截,然后通过Request包装类接管应用服务器的Session管理。在Request包装类中重写getSession方法。让用户在进行Session读写的时候去Redis中进行操作,而且使用Session的方法与过去一样,使得管理方案对用户透明。

在Session共享模块与Redis之间,基于jedis开发了一个分布式缓存SDK,用于进行通信,同时SDK可以提供扩展性,后续如果需要支持其他的缓存服务器,只要对SDK进行扩展开发即可。

然后为了保证Session集中管理方案的高可用,将会搭建Redis集群来存储Session对象。下面是一个推荐客户搭建的最小Redis集群,集群中共有4个Redis节点,两主两从。两个Master节点用来对Session数据进行分片存储,而Slaver节点用来对Matser进行数据备份和读写分离。

三、微服务系统告别session,引入jwt

在微服务中抛弃session

在微服务体系架构中,微服务应用是由多个相互独立的微服务进程组成的,对每个微服务的访问都需要进行用户认证。微服务应用应遵循单一职责原理,即一个微服务只处理单一的业务逻辑。认证和鉴权的公共逻辑不应该放到微服务实现中。因此需要考虑一个抽象、公共的逻辑,统一对用户进行身份认证和鉴权服务。

(简而言之:Redis集中存储与微服务的理念相冲突。但实际上在微服务中继续使用Redis集中存储方案也是可行的,只是一般不会这么干!)

下面的问答也说明了这个问题,来源于多个微服务之间的session共享问题

问题:
现在我们有一个zuul+redis+springcloud,然后有多个springboot做的微服务,其中有一个专门做个人中心的微服务,我们会在这个服务做注册登录操作,然后别的微服务做业务处理。
因为是第一次做,不知道这个网关究竟可不可以做到多个微服务之间的session共享,就是我们在微服务A做了登录操作,保存用户信息到session,然后在微服务B里面取到用户信息。
多个微服务的项目名是不一样的。如果是同一个微服务,部署在不同的服务器上面这种情况我们是可以做到session共享。

某个回答:
不建议系统设计成这样子
微服务连数据库都是隔离的,你这连缓存都能共享,这个不合理,各个服务都能访问session,如果个人中心升级,session存储的对象结构变化其他服务是不是都得升级?
服务倒是可以有办法多个版本兼容,但你session只有一个,你这耦合度太高,有违微服务架构的初衷。
建议做成松散的授权登录模式比较好 

解决方案

1.用户身份的认证:

由于在微服务架构中以API Gateway作为对外提供服务的入口,因此可以考虑在API Gateway处提供统一的用户认证。具体技术实现可以采用Zuul+Spring Security+OAuth2/JWT。

2.用户状态的保持:

在单体应用时,我们是在服务器端采用Session和客户端采用Cookie来保存用户状态,由于在服务器是有状态的,对服务器的水平扩展有影响。而微服务架构的优势之一就是微服务的水平扩展和弹性,所以微服务最好是无状态的,因此建议采用Token来记录用户登录状态。token会存储在客户端中,其工作流程与session/cookie那一套实际上是类似。

3.用户注销:

由于Token存储在客户端而非服务端,当用户注销时,Token的有效时间还没有到,还是有效的。所以如何在用户注销登录时让Token注销是一个要关注的点。一般有如下几种方式:

Token存储在Cookie中,这样客户端注销时,自然可以清空掉

将Token存放到分布式缓存中,每次校验Token时区检查下该Token是否已注销。不过这样也就失去了快速校验Token的优点。(不推荐)

多采用短期令牌,比如令牌有效期是30分钟,这样可以一定程度上降低注销后 Token可用性的风险。

4.用户的权限控制:

API Gateway处进行统一的权限控制
客户端发送的HTTP请求中包含有请求的Resource及HTTP Method。如果系统遵循REST规范,以URI资源方式对访问对象进行建模,则API Gateway可以从请求中直接截取到访问的资源及需要进行的操作,然后调用Security Service进行权限判断,根据判断结果决定用户是否有权限对该资源进行操作,并转发到后端的Business Service。这种实现方式API Gateway会统一处理认证和鉴权逻辑,各个微服务不需要考虑用户认证和鉴权,只需要处理业务逻辑,简化了各微服务的实现。

5.服务间的认证:

微服务应用,除了来自用户和第三方的访问外,还有大量的微服务之间访问。根据微服务应用的数据敏感程度的不同,对于微服务之间的相互访问可能有不同的安全要求

  • 微服务间的相互访问不进行认证和鉴权
    1.依托网络安全措施,来保障微服务间的通讯安全
    2.微服务提供的数据敏感程度不是很高。
    在这种情况下,一旦攻击者侵入到内部网络后没有了保护措施。虽然微服务的数据敏感程度不高,但攻击行为仍给我们带来危害。
  • 微服务间的相互访问采用颁发访问凭证进行安全控制
    微服务在使用的维度上,我们定义服务的调用方和服务的提供方。服务的提供方对调用方颁发访问凭证,提供方对访问严格控制;
    没有访问凭证的访问,拒绝访问;根据不同的访问凭证类型,安全控制不同的访问类型。
  • 微服务间的相互访问采用Service Account进行安全控制
    Istio-Auth提供强大的服务间认证和终端用户认证,使用交互TLS,内置身份和证书管理。可以升级服务网格中的未加密流量,并为运维人员提供基于服务身份而不是网络控制来执行策略的能力。Istio的未来版本将增加细粒度的访问控制和审计,以使用各种访问控制机制(包括基于属性和角色的访问控制以及授权钩子)来控制和监视访问您的服务,API或资源的人员。
    Istio官网:https://istio.io/docs/concepts/security/

jwt官网:https://jwt.io/

Oauth官网:https://www.oauth.com

CAS官网:https://www.apereo.org/projects/cas

 

 

 

参考:

如何构建安全的微服务应用

微服务统一登陆认证怎么做?JWT ?

Spring Cloud下微服务权限方案(老A)

posted @ 2019-04-13 23:46  静水楼台/Java部落阁  阅读(271)  评论(0编辑  收藏  举报