与 SSO 相对应,UIMS 应该支持一次登出,全部登出,即 SSOff(Single Sign-Off,非标准术语);或者一次登出,部分登出,而是否全部登出或部分登出取决于用户的选择,例如用户在 Web 端登出后,是否无线端 APP 也登出,这取决于用户偏好,但系统应当提供这种能力。
此外,必须提供统一的销毁功能,以支持用户删除其账户,一次销毁,全部销毁。
云平台应具备付费授权机制,针对用户账户和组织账户进行独立授权。根据产品的商业策略,可执行灵活的付费模式:
上文基于『统一身份治理』的理念,提出了统一身份管理系统(UIMS)下关于身份认证和授权部分的主要需求。目前实现统一身份认证和授权的技术手段较多,总体可以归纳为以下两类:
具体有:
上述方案各有利弊:
分布式 Session 是老牌的成熟解决方案,但因其状态化通信的特性与微服务提倡的API导向无状态通信相互违背,且共享式存储存在安全隐患,因此微服务一般不太采用。
OAuth2.0 是业内成熟的授权登录解决方案,然而 OA2.0 提供了4种授权模式,能够适应多种场景,作为基于令牌的安全框架,可以广泛用于需要统一身份认证和授权的场景。
关于 OAuth2.0 的介绍,请参考 http://www.ruanyifeng.com/blog/2014/05/oauth_2_0.html
在 OAuth2.0 的实施过程中,一般会采用 JWT 作为令牌的主要标准:JWT(JSON Web Token)是一种简洁的自包含的 JSON 声明规范,因其分散存储和自解签等特点而广泛应用于非集中式认证/授权场景。由于 JWT 信息是经过签名的,可以确保发送方的真实性,确保信息未经篡改和伪造。但由于其自包含的客户端验签特性,令牌一经签发,即无法撤销,因此单纯采用 JWT 作为统一身份认证和授权方案无法满足帐号统一登出和销毁、帐号封禁和解除这几种类型的需求,所以一般配合 OAuth2.0 一起使用。
关于 JWT 的介绍,请参考 http://blog.leapoahead.com/2015/09/06/understanding-jwt/
关于 CAS 的介绍,请参考 https://apereo.github.io/cas/
在微服务架构下,身份认证和用户授权通常分离出来成为独立的 IDP (Identity Provider)服务。在做技术选型时,应从以下几点考虑:
综合考虑,推荐采用无状态 API 模式,其中基于 OAuth2.0 的方案能够完全满足。
场景假设:构建基于图像的物品识别系统(Image-Based Classification System)
为便于理解统一认证和授权方案的细节,假定一种场景:团队准备构建一套基于图像的物品识别系统,允许用户通过 H5 应用或 APP 上传图像,系统分析后返回识别结果;同时期望将此系统开放给社区和行业用户以便商用;最后允许第三方应用将自身的功能接入 IBCS 以增强后者的能力。
下图是该系统的微服务架构图:
在微服务架构下,IBCS 分为内外两层,内层处于物理内网环境下,也称为内部服务,外层处于物理外网环境下,也称为外部服务,内外通过 API 网关连接。
下文将以物品识别系统为例子,介绍这两种推荐方案:
其中密码模式常用于外部服务的认证、授权和鉴权,客户端模式常用于内部服务的认证、授权和鉴权和开放平台应用的授权,授权码模式常用于社会化登录和 SSO,因此 OAuth2.0 可作为完整的统一身份认证和授权方案。
必须注意的是,这些角色是相对的概念。
接口 | 描述 | body | 返回 | 权限 |
---|---|---|---|---|
POST /image-classify | 图像识别 | { 图片内容, token } | { 识别结果 } | 受控接口 |
功能/API | 描述 | body | 返回 | 权限 |
---|---|---|---|---|
POST /accounts/ | 注册接口 | { username, password } | { sign-up-result } | 非受控接口 |
POST /accounts/login | 登录接口 | { username, password } | { token } | 受控接口 |
POST /accounts/logout | 登出接口 | { token } | { logout-result } | 受控接口 |
SignUp-Page | 统一注册页面(UI) | 非受控页面 | ||
Login-Page | 统一登录页面(UI) | 非受控页面 |
其中,注册接口、SignUp-Page 和 Login-Page 页面是非受控接口/页面,意味着无须鉴权即可访问。
SignUp-Page 和 Login-Page 页面是由 UIMS 提供的统一的注册和登录页面,当外部服务发起注册或登录请求时,有两种作法:一是统一跳转到 UIMS 的注册或登录页面,用户完成操作后调用 UIMS 的注册和登录 API 完成请求;二是在自己的注册和登录页面完成操作,然后以用户名和密码作为参数调用 UIMS 的注册和登录 API 完成请求。推荐采用第一种方法,类似于全网通行证,用户体验统一,不用重复开发注册登录页面。
在更高安全性要求的场景下,也会采用授权码模式。
一般来说,应当独立建设一个开放平台,开发平台作为整个云平台的一个子系统,同样依赖于 UIMS。在开放平台上,应当提供一套完善的界面和流程,以引导用户完成开发者认证和第三方应用接入的所有工作。此外,在前期阶段,也可以采用线下申请的方式,由管理员人工审核,在后台手动录入。
在开放平台上,创建第三方应用的流程和步骤,与上一步骤『成为开发者,获取 IBCS 的能力集』一致。所不同的是,上个步骤是获取 IBCS 的能力,而本步骤『创建第三方应用』,是基于开放平台开发应用,类似于微信小程序。
应该允许开发者将异构系统(第三方应用)接入 IBCS,以增强 IBCS 的能力。例如,假设 IBCS 本身不具备识别特种汽车的能力,但允许接入其他开发者开发的基于图像的特种汽车识别应用。
第三方应用接入,归属于开放平台的范畴。接入的流程和步骤,与第三步骤『成为开发者,获取 IBCS 的能力集』一致,由开放平台提供标准的 API,第三方按照接入规范执行。
场景 | 描述 | 适用模式 |
---|---|---|
用户注册(外部服务) | 用户在 APP 提供的注册页面,完成注册请求 | 非受控接口,无须鉴权 |
用户登录(外部服务),返回 token | 用户在 APP 提供的登录页面,完成登录请求,获得 token | 密码模式(resource owner password credentials) |
用户注册(UIMS) | 用户跳转到 UIMS 的注册页面,完成注册请求,注册成功后,跳回到原服务 | 非受控接口,无须鉴权 |
用户登录(UIMS),返回 token | 用户跳转到 UIMS 的登录页面,完成登录操作,获得授权码,然后携带授权码跳转到重定向URI,再获得 token | 授权码模式(authorization code) |
外部服务的鉴权 | 用户在 APP 上使用图像识别服务,APP 调用 IBCS 的图像识别 API 并返回结果给用户 | 密码模式(resource owner password credentials) |
内部服务的鉴权 | 图像识别服务向配置服务获取配置信息 | 客户端模式(client credentials),或简单的 HTTP Basic 验证 |
开发者:获取 IBCS 能力集 | 客户端模式(client credentials)或授权码模式(authorization code) | |
开发者:创建第三方应用 | 客户端模式(client credentials)或授权码模式(authorization code) | |
开发者:接入第三方应用 | 客户端模式(client credentials)或授权码模式(authorization code) |
服务鉴权,从形式上分为:
例如,用户通过 APP 登录 IBCS 后,访问图像识别服务的过程:用户登录后获得 token,由 APP 携带此 token 向图像识别服务发起请求,图像识别服务首先调用 IDP 服务验证 APP 的身份(通过 ClientId 和 ClientSecret),然后再验证用户的身份(通过 token),如果 APP 和用户都获得授权,则请求通过,返回识别结果。
浏览器的同源策略给 Web 应用划定了安全边界,是 Web 应用安全模型的重要基础。基于令牌的安全系统,在同源策略的约束下面临两个问题:
第一个问题,一般采用 CORS 方案,在服务端的响应头声明 Access-Control-Allow-Origin 参数即可解决跨域请求的问题。
第二个问题,在同域环境下,传统方法是采用 Cookie 的方案。跨域环境下,也有几种方案,从安全性和简便性考虑,推荐采用这种方案:
OAuth2.0 是集中式的令牌安全系统,可以通过撤销令牌登出系统。关闭账户与此类似。
可在 IDP 服务或 API 网关增加规则过滤器,将商业授权策略应用到授权规则中。
后续会写实践篇,敬请期待……
JWT 是一种自包含的客户端令牌系统技术规范,这是其与 OAuth2.0 默认令牌的最大不同,在应用 JWT 时,有几个要点须加以说明。
由于 JWT 属于自包含的客户端令牌系统,令牌发出后无须服务器验证,只需在客户端验证。客户端验证并解签后将得到必要的信息,例如用户基本信息和权限标识符。这种设计天然地存在无法撤销令牌的问题。解决方案是网关之外的外部服务继续使用 OAuth2.0 的 AccessToken,在网关以内的内部服务使用 JWT,这样做有几个好处:
不过此方案仍然存在两个问题:
与 OAuth2.0 方案一致,客户端同样需要使用 ClientId 和 ClientSecret 认证/鉴权。
JWT 一般采用非对称加密算法对 Header 和 Payload 进行签名,公钥可以公开存储在外部服务中,如 H5、APP。
非对称算法的重要特点是,使用密钥加密时,必须用公钥解密;用公钥加密时,必须用密钥解密。利用此特性,通常在服务端采用密钥加密信息,然后客户端采用公钥解密信息。由于密钥存储在服务端,因此安全性高;公钥本身可以公开,因此可以在客户端存储。
JWT 经由服务端用密钥加密附加签名后,发往客户端,客户端使用公钥进行解密验签,如果签名校验通过则信任该 JWT。JWT 包含了丰富的信息(通常是用户基本信息和权限标识符),验签通过后客户端完全可以信任此 JWT,因此不必再依赖于服务端重复鉴权。值的注意的是,JWT的前两部分 Header 和 Payload 仅采用 Base64 编码,因此与明文无异,不应在 JWT 中存储敏感信息。
以 IBCS 为例,当图像识别服务服务携带 JWT 向配置服务请求资源时,配置服务使用公钥解密,配置服务完全可以信任图像识别服务,因此也不必再依赖于鉴权服务的重复认证/鉴权。对于安全性要求不高的场景,也可以使用 HTTP Basic 验证进行简单认证/鉴权甚至不认证/鉴权。
同样,外部的 APP 携带 Oauth AccessToken 向内网的图像识别服务发起请求时,属于外部服务向内网服务发起请求,必须经过 API 网关,由网关执行规则过滤和代理认证(网关向 IDP 请求校验令牌),确保 AccessToken 仍处于有效状态,如果 Token 通过检验,则由 IDP 生成包含权限标识(或Scope)的 JWT 返回给网关,网关拿到 JWT 后利用公钥进行解密,并校验权限标识(或Scope),通过后再携带此 JWT 向图像识别服务转发请求,图像识别服务收到请求后,利用公钥解密 JWT 并自行检验其有效性、获取用户信息等,无须再请求 IDP。
必须留意,在网关拿到 JWT 以后,虽然可以连同 Oauth AccessToken 一起缓存,下次该服务再发起请求时,可直接转发 JWT 而不用再经由 IDP 的进行 JWT 令牌转换,但这么做有两个问题:
所以,综上所述,不建议网关缓存 JWT 并直接转发。
与 OAuth2.0 的跨域解决方案一致。
本文给出了微服务架构下的统一身份认证和授权的设计方案,从平台级 SaaS 模式下『统一身份治理』的概念出发,梳理了关键的需求点,提出了对应的解决方案。其中 OAuth2.0 是最佳解决方案,不过在实际运用中,应当遵循『合适原则』、『简单原则』和『演化原则』三个原则,不能盲目照搬。