微服务架构下的安全认证与鉴权

从单体应用架构到分布式应用架构再到微服务架构,应用的安全访问在不断地经受考验。为了适应架构的变化、需求的变化,身份认证与鉴权方案也在不断地变革。面对数十个甚至上百个微服务之间的调用,如何保证高效安全的身份认证是个难题。面对外部的服务访问,如何提供细粒度的鉴权方案也是个难题。

单体应用VS微服务

随着微服务架构的兴起,传统的单体应用场景下的身份认证和鉴权面临的挑战越来越大。

在单体应用体系下,应用是一个整体,一般针对所有的请求都会进行权限校验。请求一般会通过一个权限的拦截器进行权限的校验,在登陆时将用户信息缓存到Session中,后续访问则从缓存中获取用户信息。

而在微服务架构下,一个应用会被拆分成若干个微应用,每个微应用都需要对访问进行鉴权,每个微应用都需要明确当前访问用户以及其权限。尤其是当访问来源不只是浏览器,还包括其他服务的调用时,单体应用架构下的鉴权方式就不是特别合适了。在微服务架构下,要考虑外部应用接入的场景、用户-服务的鉴权、服务-服务的鉴权等多种鉴权场景。

David Borsos在伦敦的微服务大会上提出了四种方案:

1.单点登陆(SSO)。这种方案意味着,每个面向用户的服务都必须与认证服务交互,会产生大量非常琐碎的网络流量和重复的工作,当动辄数十个微应用时,这种方案的弊端会更加明显。

2.分布式Session方案。分布式会话方案的原理主要是讲关于用户认证的信息存储在共享存储中,且通常由用户会话作为key来实现的简单分布式哈希映射。当用户访问微服务时,用户数据可以从共享存储中获取。在某些场景下,这种方案很不错,用户登陆状态是不透明的。同时也是一个高可用且可扩展的解决方案。这种方案的缺点在于,共享存储需要一定的保护机制,因此需要通过安全链接来访问,这时解决方案的实现就通常具有相当高的复杂性了。

3.客户端Token方案。令牌(Token)在客户端生成,由身份验证服务进行签名,并且必须包含足够的信息,以便可以在所有的微服务中建立用户身份。令牌会附加到每个请求上,为微服务提供用户身份验证,这种解决方案的安全性相对较好,但是身份验证的注销是一个大问题,缓解这种情况的方法可以使用短期令牌和频繁检查认证服务等。对于客户端令牌的编码方案,Borsos更喜欢使用JSON Web Tokens(JWT),它足够简单,且库支持程度也比较好。

4.客户端Token与API网关结合。这个方案意味着所有的请求都会通过网关,从而有效地隐藏了微服务。在请求时,网关将原始用户令牌转换为内部会话ID令牌。在这种情况下,注销就不是问题,因为网关可以在注销时撤销用户的令牌。

微服务常见安全认证方案

微服务常见安全认证方案主要由三种:HTTP基本认证、基于Session的认证和基于Token的认证。

HTTP基本认证(HTTP Basic Authentication)

HTTP基本认证是HTTP1.0提出的一种认证机制,过程如下:

1.客户端发送HTTP Request给服务器。

2.因为Request中并没有包含Authorization Header,服务器就会返回一个401 Unauthozied给客户端,并且在Response的Header的【WWW-Authenticate】属性中添加信息。

3.客户端把用户名和密码用BASE64加密后,放在Authorization Header中发送给服务器,认证成功。

4.服务器将Authorization Header中的用户名和密码取出,进行验证,如果验证通过,将根据请求,发送资源给客户端。

基于Session的认证

基于Session的认证应该是最常用的一种认证机制了。用户登陆认证成功后,将用户相关数据存储到Session中。单体应用架构中,默认Session会存储在应用服务器中,并且将SessionID返回到客户端中,存储到浏览器的Cookie中;分布式架构中,Session存放于某个具体的应用服务器自然是无法满足使用,简单的可以通过Session复制或Session粘滞的方案来解决。

Session复制依赖于应用服务器,需要应用服务器有Session复制能力,不过现在大部分应用服务器如Tomcat、JBoss和WebSphere等都提供了这个能力。

除此之外,Session复制的一大缺陷在于,当节点数比较多时,大量的Session数据复制会占用较多的网络资源。Session粘滞是通过负载均衡器,将统一用户的请求都分发到固定的服务器节点上,这样就保证了对某一个用户而言,Session数据始终是正确的。不过这种方案依赖于负载均衡器,并且只能满足水平扩展的集群场景,无法满足应用分割后的分布式场景。

在微服务架构下,每个微服务拆分的粒度会很细,并且不只有用户和微服务打交道,更多的还有微服务之间的调用。这个时候,上述两个方案都无法满足,就要求必须要将Session从应用服务器中剥离出来,存放在外部进行集中管理。可以是数据库,也可以是分布式缓存,比如Memchached、Redis等。这正是David Boros建议的第二种方案:分布式Session方案。

基于Token的认证

随着Restful API、微服务的兴起,基于Token的认证现在已经越来越普遍。Token和SessionID不同,并非只是一个key。Token一般会包含用户的相关信息,通过验证Token就可以完成身份校验。像Twitter、微信、QQ、Github等公有服务的API都是基于这种方式进行认证的,一些开发框架如OpenStack、Kubernates内部API调用也是基于Token认证。基于Token认证的一个典型流程如下:

1.用户输入登陆信息(或者调用Token接口,传入用户信息),发送到身份认证服务进行认证(身份认证服务可以和服务端在一起,也可以分离,看微服务拆分情况)。

2.身份认证服务验证登陆信息是否正确,返回Token(一般Token中会包含用户基础信息、权限范围、有效时间等信息),客户端存储Token,可以存储在Session或者数据库中。

3.用户将Token放在HTTP请求头中,发起相关API调用。

4.被调用的微服务,验证Token权限。

5.服务端返回相关资源和数据。

基于Token认证的好处

1.服务端无状态。Token机制在服务端不需要存储Session信息,因为Token自身包含了所有用户的相关信息。

2.性能较好。因为在验证Token的时候不用再去访问数据库或者远程服务进行权限校验,自然可以提升不少性能。

3.支持移动设备。

4.支持跨程序调用。Cookie是不允许跨域访问的,而Token则不会存在这个问题。

转自:https://mp.weixin.qq.com/s/x0CZpovseOuofTA_lw0HvA

"我从来没有被谁捧在手心里真正地爱过,每一次我都好像在克制自己,不要发脾气,要懂事,可是只有我自己知道,我有多么难过,多么心累。"

原文地址:https://www.cnblogs.com/yanggb/p/11090028.html