html
java
目录web
- 1. 什么是单点登陆
- 2. 用户登陆
- 2.1 认证方式
- 2.2 受权方式
- 2.3 第一方登陆架构实现
- 2.4 第三方登陆架构实现
- 2.5 第一方登陆和第三方登陆的受权区别
- 2.6 登陆架构实现小结
- 3. 权限控制
- 3.1 分布式鉴权架构
- 3.2 集中式鉴权架构
- 3.3 分布式和集中式鉴权的优缺点
- 3.4 访问控制的粒度
- 3.4.1 Http方法级别
- 3.4.2 API接口级别
- 3.4.3 API实现级别
- 4. 小结
- 5. 参考资料
在互联网应用开发中,应用服务的用户登陆和权限控制是相当重要的一个环节,直接影响到应用的安全运营,也影响到用户的隐私保护,所以用户登陆和权限控制是互联网应用开发的必要功能组件, 其涉及到认证、受权、鉴权和权限控制四个功能环节。本文将梳理互联网应用开发中的单点登陆(single-sign-on)技术架构实现,单点用户登陆也被称为统一用户登陆。redis
- 注1:本文讨论的互联网应用开发,主要是指web应用和移动应用开发两个技术领域。
- 注2:本文所讨论的认证、受权、鉴权和权限控制的概念定义来自其这篇文章。所以,在阅读本文以前,建议先请阅读前篇文章。
1. 什么是单点登陆
单点登陆SSO不只仅是实现用户登陆这单一功能,它更是一个技术架构,一个解决方案,可以提供统一的认证、受权、鉴权和权限控制,提供相应的组件,方便用户的使用,以及应用的开发快速接入。因此,单点登陆不是一个简单的登陆模块。spring
单点登陆,从字面来讲,是让用户使用同一帐号能够访问不一样应用服务,并且用户只需登陆一次(输入一次用户名和密码)即可实现屡次受权。单点登陆可以很大程度上方便用户的登陆操做。这是从用户的角度出发来看单点登陆。后端
单点登陆还须要考虑的另一个重要需求,是方便应用的对接使用,单点登陆架构必须提供相应的客户端组件和配置,使得应用能够简单、方便、快速地接入单点登陆功能,同时实现安全的权限控制。跨域
所以,单点登陆做为一个安全技术架构,其主要包括用户登陆和权限控制两大功能需求,前者涉及认证和受权环节,后者涉及鉴权和权限控制环节。浏览器
2. 用户登陆
用户登陆的过程通常会涉及到用户认证和受权两个环节,这两个环节每每一并发生,即在确认用户身份的同时,也完成用户的受权。缓存
根据登陆功能模块的提供方,能够将登陆划分为第一方登陆和第三方登陆两种类型,安全
- 第一方登陆:应用的登陆服务由本身提供。因为是己方登陆和己方应用,因此登陆服务和应用服务之间相互可信,这大大方便了受权过程。
- 第三方登陆:应用的登陆服务由第三方提供,使用第三方的用户帐号登陆,好比经过微信、QQ、支付宝帐号进行登陆等等。目前各大互联网开放平台大多采用业界标准的OAuth 2.0受权码模式实现第三方登陆。
第一方登陆和第三方登陆,在用户认证技术的实现上没有太大差异,可是受权流程有区别。具体的受权流程和区别在下文的架构实现中讨论。
2.1 认证方式
在互联网开发中,常见的认证方式有,
- 用户名和密码
- 手机短信验证码
- 手机应用二维码扫描
- 用户手势
- 基于时间序列和用户相关的一次性口令
本文为了方便讨论,将使用简单的http基本认证(http basic authentication)方式进行用户登陆,即用户名和密码的方式。更多的认证方式,通常能够经过identity provider的扩展接口来实现。
2.2 受权方式
一旦用户登陆成功,便可获取到相应的受权信息。
在互联网应用开发领域,受权的实现技术主要包括以下几种,
- 经过web服务器的session机制,一个访问会话保持着用户的受权信息
- 经过web浏览器的cookie机制,一个网站的cookie保持着用户的受权信息
- 颁发受权令牌(token),一个合法有效的令牌中保持着用户的受权信息
前面二者常见于web开发,须要有浏览器的支持。而对于移动应用及其其它没法使用cookie的场景中,大多能够采用token的实现并经过header方式携带该受权信息在请求中。
本文为了同时支持web应用和移动应用的受权,受权信息将以受权令牌(token)形式颁发,对于web应用,该受权令牌经过cookie携带于请求中,而对于移动应用,则经过header方式携带于请求中。
2.3 第一方登陆架构实现
因为是己方登陆实现,因此登陆服务和应用服务之间相互可信,这大大方便了受权过程。
在第一方登陆的场景下,通常能够经过两种方式得到受权,
- 若应用经过浏览器访问,则能够经过同域cookie方式实现共享受权
- 若应用不是浏览器访问,或者没法经过cookie技术,则能够直接经过用户名和密码来换取受权。须要注意的是,应用服务能够拿到用户名和密码等敏感信息,这是基于可信应用的先决条件。
代码实现(待开发)
一个简单的架构实现以下,
图中亮红色线和方格为单点登陆架构所需实现的组件和功能,其主要包括,
- 单点登陆模块:提供用户登陆界面,实现跳转返回,受权令牌(token)的颁发、校验和注销
- Web filter:获取请求中的受权令牌并校验,若合法则经过请求,不然返回错误消息。
对于web应用,经过共享cookie的方式获取受权,整个流程交互以下,
- 用户经过浏览器访问web服务
- 后端服务中一个通用的web filter校验请求,若发现请求中没有受权令牌,则跳转至用户登陆模块,让用户进行登陆
- 用户输入用户名和密码,若登陆成功,则将受权令牌存储在浏览器的cookie中
- 将用户跳转回用户的访问页面,此时请求中cookie将自动带上受权令牌
- 后端服务的web filter校验请求cookie中的受权令牌,若合法且有效,则用户能够正常访问后端服务,不然返回错误消息,提示用户再次登陆。
- 用户注销登陆时,web应用服务将存储在浏览器cookie中的受权令牌清除,并注销redis中的令牌。
对于移动应用,经过用户名和密码的方式获取受权,整个流程交互以下,
- 用户打开移动应用,应用提示用户登陆
- 用户输入用户名和密码,若登陆成功,则将受权令牌返回给移动应用,存储在手机上的应用存储空间。
- 进入应用后,移动应用访问后端服务,受权令牌携带在请求header中
- 后端服务中一个通用的web filter对请求header中的受权令牌进行校验,若合法且有效,则用户能够正常访问后端服务,不然提示用户登陆。
- 用户注销登陆时,移动应用将受权令牌清除,并注销redis中的令牌。
因为移动应用没法像web应用同样,经过浏览器cookie的方式自动携带受权信息,移动应用须要本身处理受权信息的存储和请求发送。
2.4 第三方登陆架构实现
相比于第一方登陆,第三方登陆最大的好处在于,可让用户使用一个经常使用的第三方帐号直接登陆,例如微信、QQ、淘宝帐号等,省去了用户注册帐号的步骤,也免去用户记忆各类应用帐号密码的烦恼,方便了用户的快速使用,进而下降用户接入成本。
对于第三方登陆,目前各大互联网开放平台大多采用业界标准的OAuth 2.0受权码模式。对于OAuth 2.0的受权码模式和更多详细介绍将有另一篇文章讨论,这里对其不扩展。
代码实现(待开发)
一个简单的架构实现以下,
图中亮红色线和方格为单点登陆架构所需实现的组件和功能,其包括,
- OAuth 2.0受权服务器:提供用户登陆受权,实现跳转返回,受权令牌(token)的颁发、校验和注销
- Token接口:用于客户端调用,经过受权码换取受权令牌
- Web filter:获取请求中的受权令牌并校验,若合法则经过请求,不然返回错误消息。
图中有两种应用类型,web应用和移动应用,两种获取受权方式基本同样。
对于web应用,整个流程交互以下,
- 用户经过浏览器访问Web服务
- 后端服务中一个通用的web filter校验请求,若发现请求中没有受权令牌,则跳转至第三方用户登陆服务
- 在第三方登陆服务中,用户输入用户名和密码,若登陆成功,则跳转回web应用,并返回受权码
- Web应用将获取到的受权码,调用后端Token接口,该接口将根据受权码+应用ID+应用Secret,向第三方申请受权令牌,若一切正常,第三方颁发受权令牌给Web应用,Web应用将获取到的受权令牌存储在浏览器的cookie中。
- 将用户跳转回用户的初始访问页面,此时请求中cookie将自动带上受权令牌
- 后端服务的web filter校验请求cookie中的受权令牌,若合法且有效,则用户能够正常访问后端服务,不然返回错误消息,提示用户再次登陆。
- 用户注销登陆时,web应用服务将存储在浏览器cookie中的受权令牌清除,并注销redis中的令牌。
移动应用和web应用的流程相似,整个流程交互以下,
- 用户打开移动应用,应用提示用户登陆,并将用户导向第三方登陆服务
- 在第三方登陆服务中,用户输入用户名和密码,若登陆成功,则跳转回移动应用,并返回受权码给移动应用。
- 移动应用将获取到的受权码,调用后端Token接口,该接口将根据受权码+应用ID+应用Secret,向第三方申请受权令牌,若一切正常,第三方颁发受权令牌给移动应用,移动应用将获取到的受权令牌存储在手机上的应用存储空间。
- 进入应用后,移动应用访问后端服务,受权令牌携带在请求header中
- 后端服务中一个通用的web filter对请求header中的受权令牌进行校验,若合法且有效,则用户能够正常访问后端服务,不然提示用户登陆。
- 用户注销登陆时,移动应用将受权令牌清除,并注销redis中的令牌。
2.5 第一方登陆和第三方登陆的受权区别
第一方登陆和第三方登陆之间最大的区别在于受权流程。
第一方登陆在用户被认证以后,即刻颁发受权令牌,应用服务通常无需介入受权流程。而第三方登陆在用户认证以后,先颁发给受权码给应用服务,应用服务还需根据这个受权码去换取受权令牌,换句话说,应用服务需介入受权流程。
这里有个问题是,为何在第三方登陆中,应用服务会被介入受权流程?主要缘由是在第三方登陆场景中,除了用户须要被认证,应用服务自己也须要被认证。而在第一方登陆场景,只需用户认证,应用服务自己是可信的,其无需被认证。
2.6 登陆架构实现小结
为了对比上述两个登陆架构实现的不一样之处,下面将各自的特色小结为下表,
第一方登陆架构 | 第三方登陆架构 | |
---|---|---|
登陆功能 | 由己方提供 | 由第三方提供 使用第三方的用户帐户 |
登陆实现 | 经过http basic auth | OAuth 2.0受权码模式 |
应用是否可信 | 可信,应用能够接触用户密码等敏感信息,应用自己无需认证 | 不可信 |
应用是否须要认证 | 否 | 是 |
应用是否能够接触用户密码等敏感信息 | 是 | 否 |
受权过程 | 登陆成功后颁发token | 1. 登陆成功后返回受权码给应用 2. 应用根据受权码和应用ID换取token |
Web页面的服务请求 | 经过cookie带上token | 经过cookie带上token |
移动应用的服务请求 | 经过header带上token | 经过header带上token |
3. 权限控制
在互联网应用开发中,安全控制在后端服务中实现。整个权限控制的过程通常会涉及到鉴权和权限控制两个环节。
鉴权的实现方式通常有两种,
- 经过受权服务器:因为受权令牌是由受权服务器颁发的,因此由受权服务器校验也是天然而然的事情。这种方式会致使受权服务器的访问热点问题,为了缓解热点,缓存是必要配置。
- 经过加解密:经过受权令牌的加解密方式,确认令牌的合法性。即,受权服务器颁发一个经过公钥加密的受权令牌,在校验的时候若可以经过私钥解密,则该令牌为合法令牌。这种方式有一个缺点是,一旦令牌注销失效后,信息没法及时通知到解密方。对令牌的注销时效性要求不高的场景下,可使用这种方式,其大大缓解了受权服务器的访问热点问题。
若根据鉴权的架构方式,则可分为分布式和集中式两大类,
- 分布式:经过后端web服务的filter实现分布式控制,在各个服务应用的运行实例中进行鉴权
- 集中式:经过网关实现集中式控制,在访问流量的入口进行鉴权
鉴权后访问控制粒度从大到小有以下三种分类,
- Http方法级别
- API接口级别
- API实现级别
下面将对鉴权的架构实现和控制粒度进行详细讨论。
3.1 分布式鉴权架构
分布式鉴权的架构以下图,
在web应用开发中,能够经过web应用服务的filter功能,对全部请求中的受权令牌进行校验,实现分布式鉴权。分布式鉴权实现简单,能够快速实现并使用,但随着应用服务架构的水平和垂直扩展,filter的升级将会成为头痛的问题。
3.2 集中式鉴权架构
集中式鉴权的架构以下图,
经过网关,在访问流量的入口,对全部请求中的受权令牌进行校验,实现集中式鉴权。集中式鉴权减轻了应用服务的接入成本,但会增长了网关的性能负荷。
3.3 分布式和集中式鉴权的优缺点
分布式鉴权和集中式鉴权有各自的优缺点小结为下表,
分布式鉴权 | 集中式鉴权 | |
---|---|---|
优势 | 简单,能够分散校验热点 | 应用服务接入成本低,方便鉴权管理 |
缺点 | filter版本升级困难,须要对全部应用服务进行依赖更新 | 须要网关的支持,而且鉴权操做将增长网关的性能负荷 |
应用场景 | 简单的互联网web应用开发 | 大型互联网web应用开发 |
3.4 访问控制的粒度
鉴权后就会获得请求访问的权限,接下来则是根据权限来控制请求访问的容许或禁止。
根据访问控制粒度从大到小,可划分出以下几个控制级别,
- Http方法级别
- API接口级别
- API实现级别
3.4.1 HTTP方法级别
若web应用服务是按照Restful的规范来开发接口服务,则能够根据Restful的定义对Http的不一样方法实现不一样的访问控制。
根据Restful的规范定义,Http方法具备以下安全性和幂等性的特色,
HTTP方法 | Restful定义 | 安全性 | 幂等性 |
---|---|---|---|
GET | 获取资源 | 是 | 是 |
POST | 建立资源 | 否 | 否 |
PUT | 更新资源 | 否 | 是 |
DELETE | 删除资源 | 否 | 是 |
HEADER | 资源元信息 | 是 | 是 |
OPTIONS | 是 | 是 |
表中,安全性和幂等性的概念以下,
- 安全性是指该方法不改变资源的状态,即不改变后台数据
- 幂等性是指该方法执行的同一操做屡次,其结果保持一致
能够看到,对于安全的HTTP方法,好比GET操做,其访问控制能够宽松。而对于一些非安全操做,则须要根据不一样权限来控制访问请求。在实际应用过程当中,能够执行以下的权限控制规则,
- 匿名用户:能够执行GET请求
- 普通登陆用户:能够执行GET、POST、PUT请求
- 管理员:能够执行全部类别请求
总的来讲,根据Http请求的方法和URI进行访问控制。
3.4.2 API接口级别
这个权限控制的粒度深刻到代码控制层(Controller),不一样的权限,能够访问不一样的API接口。
一个spring mvc的代码样例以下,
@Controller public class TokenApp { @PreAuthorize("hasAuthority('ROLE_ADMIN')") public Principal getUserInfo(Principal me){ return me; } }
上面的代码表示,具备管理员角色的权限才能获取当前用户信息。
这个粒度的权限访问控制基本能够知足大多数应用场景需求。
3.4.3 API实现级别
在应用的实现级别进行控制,这个控制粒度很是细,其根据不一样权限返回不同的调用结果,例如,一样是查看学生列表,如果班主任,则返回一个班的学生列表,如果校长,则返回一个学校的学生列表。
4. 小结
本文主要从用户登陆和权限控制两大功能方面梳理其架构实现,这些实现能够结合实际的应用场景,进行相应的匹配。
第一方登陆 | 第三方登陆 | |
---|---|---|
分布式权限控制 | 1. 简单web应用场景 2. 登陆服务和应用服务相互可信 3. 登陆服务和应用服务同域,能够受权共享 |
1. 简单web应用场景 2. 登陆服务和应用服务相互不可信 3. 登陆服务和应用服务不一样域,各自独立开发部署,没法受权共享 4. 应用和登陆服务模块完全解耦,经过跨域跳转实现用户登陆。 |
集中式权限控制 | 1. 大型web应用场景,有网关组件部署 | 1. 大型web应用场景,有网关组件部署 2. 快速接入第三方用户 |