一、什么是单点登录
单点登录的英文名叫做:Single Sign On(简称SSO),指在同一帐号平台下的多个应用系统中,用户只需登录一次,即可访问所有相互信任的系统。简而言之,多个系统,统一登陆。
为什么需要做单点登录系统呢?在一些互联网公司中,公司旗下可能会有多个子系统,每个登陆实现统一管理,多个账户信息统一管理 SSO单点登陆认证授权系统。比如阿里系的淘宝和天猫,显而易见这是两个系统,但是在使用过程中,只要你登录了淘宝,同时也意味着登录了天猫,如果每个子系统都需要登录认证,用户早就疯了,所以我们要解决的问题就是,用户只需要登录一次就可以访问所有相互信任的应用系统。
二、单点登录原理
sso需要一个独立的认证中心,所有子系统都通过认证中心的登录入口进行登录,登录时带上自己的地址,子系统只接受认证中心的授权,授权通过令牌(token)实现,sso认证中心验证用户的用户名密码正确,创建全局会话和token,token作为参数发送给各个子系统,子系统拿到token,即得到了授权,可以借此创建局部会话,局部会话登录方式与单系统的登录方式相同。
三、单点登录实现方式
单点登录的实现方案,一般就包含:Cookies,Session同步,分布式Session,目前的大型网站都是采用分布式Session的方式。
1.基于Cookie+Redis的单点登录
最简单的单点登录实现方式,用cookie作为媒介存放用户凭证。 用户登录系统之后,会返回一个加密的cookie,当用户访问子应用的时候会带上这个cookie,授权以解密cookie并进行校验,校验通过后即可登录当前用户。
redis:在key:生成唯一随机值(ip、用户id等等),在value:用户数据
cookie:把redis里面生成key值放到cookie里面
下面对上图简要描述
- 用户访问系统1的受保护资源,系统1发现用户未登录,跳转至sso认证中心,并将自己的地址作为参数
- sso认证中心发现用户未登录,将用户引导至登录页面
- 用户输入用户名密码提交登录申请
- sso认证中心校验用户信息,创建用户与sso认证中心之间的会话,称为全局会话,同时创建授权令牌
- sso认证中心带着令牌跳转会最初的请求地址(系统1)
- 系统1拿到令牌,去sso认证中心校验令牌是否有效
- sso认证中心校验令牌,返回有效,注册系统1
- 系统1使用该令牌创建与用户的会话,称为局部会话,返回受保护资源
- 用户访问系统2的受保护资源
- 系统2发现用户未登录,跳转至sso认证中心,并将自己的地址作为参数
- sso认证中心发现用户已登录,跳转回系统2的地址,并附上令牌
- 系统2拿到令牌,去sso认证中心校验令牌是否有效
- sso认证中心校验令牌,返回有效,注册系统2
- 系统2使用该令牌创建与用户的局部会话,返回受保护资源
用户登录成功之后,会与sso认证中心及各个子系统建立会话,用户与sso认证中心建立的会话称为全局会话,用户与各个子系统建立的会话称为局部会话,局部会话建立之后,用户访问子系统受保护资源将不再通过sso认证中心,全局会话与局部会话有如下约束关系
- 局部会话存在,全局会话一定存在
- 全局会话存在,局部会话不一定存在
- 全局会话销毁,局部会话必须销毁
Cookie的作用在于充当一个信息载体在Server端和Browser端进行信息传递,而Cookie一般是以域名为分割的,例如a.xxx.com与b.xxx.com的Cookie是不能互相访问的,但是子域名是可以访问上级域名的Cookie的。 即a.xxx.com和b.xxx.com是可以访问xxx.com下的Cookie的,于是就能将顶级域名的Cookie作为OpenId的载体。
验证步骤和上第二个方法非常相似:
- 在提供验证服务的站点里登录;
- 将OpenId写入顶级域名Cookie里;
- 访问子系统(Cookie里带有OpenId)
- 子系统取出OpenId通过并向验证服务发送OpenId
- 返回用户认证信息
- 返回授权后的内容
但使用该方式把信任存储在客户端的Cookie中会有两个问题:
- Cookie不安全
- 不能跨域实现免登
对于第一个问题,通过加密Cookie可以保证安全性,当然这是在源代码不泄露的前提下。如果Cookie的加密算法泄露,攻击者可以通过伪造Cookie伪造成特定用户身份。 对于问题二更是硬伤,所以才有了以下的分布式session方案。
2.分布式session方式实现单点登录
流程运行:
(1) 用户第一次登录时,将会话信息(用户Id和用户信息),比如以用户Id为Key,写入分布式Session;
(2) 用户再次登录时,获取分布式Session,是否有会话信息,如果没有则调到登录页;
(3) 一般采用Cache中间件实现,建议使用Redis,因此它有持久化功能,方便分布式Session宕机后,可以从持久化存储中加载会话信息;
(4) 存入会话时,可以设置会话保持的时间,比如15分钟,超过后自动超时;
结合Cache中间件,实现的分布式Session,可以很好的模拟Session会话。
3.通过页面重定向的方式
最后一种介绍的方式,是通过父应用和子应用来回重定向中进行通信,实现信息的安全传递。 父应用提供一个GET方式的登录接口,用户通过子应用重定向连接的方式访问这个接口,如果用户还没有登录,则返回一个的登录页面,用户输入账号密码进行登录。如果用户已经登录了,则生成加密的Token,并且重定向到子应用提供的验证Token的接口,通过解密和校验之后,子应用登录当前用户。
这种方式较前面两种方式,接解决了上面两种方法暴露出来的安全性问题和跨域的问题,但是并没有前面两种方式方便。 安全与方便,本来就是一对矛盾。
4.使用token实现
1.在项目某个模块进行登录,登录之后,按照规则生成字符串,把登陆之后用户包含到生成字符串里面,把字符串返回
(1)可以把字符串通过cookie返回
(2)把字符串通过地址栏返回
2.再去访问项目其他模块,每次访问在地址栏带着生成的字符串,在访问模块里面获取地址字符串,根据字符串获取用户信息。如果可以获取到就能登录。
实现方式如下图: