认证 - 18965050/authz GitHub Wiki
登录部分分为以下几种情况:

简单说明如下:
- 用户访问某个需要认证的url,比如
a.com/test1, 会根据a.com应用中sid cookie来判断session是否登录.未登录情况下, 应用组装ct(client token)并重定向到auth.xyz.cn/getTicket?ct=xxx连接 -
auth.xyz.cn获取ct参数并组装到AuthUserInfo对象, 将其存储到session中, 由于此时session并未登录, 返回登录请求auth.xyz.cn/login - 浏览器重定向到登录页面, 选择登录方式, 填写登录参数(用户名, 密码等),进行登录.
- 登录成功后, 根据session中的AuthUserInfo对象获取ct参数,记录登录行为到日志(比如登录来源, 登录方式等等), 并生成st(server token),缓存st中ticket和userInfo之间的绑定关系(关系解除是通过redis的expireTime实现),绑定GSID和sessionId,从session中删除AuthUserInfo对象. 从ct中获取client callback url,并携带st参数进行重定向
-
a.com应用中的filter处理上一步中的callback url,先对st参数进行校验(比如版本号, ticket是否在有效期内). 校验成功则重定向到auth.xyz.cn/getUserInfo,获取用户信息 -
auth.xyz.cn对getUserInfo连接进行处理, 先判断ticket是否有效, 再从缓存中根据ticket取出userInfo返回给a.com -
a.com从auth.xyz.cn中获取用户信息后,执行后续登录流程. 包括从st中取出GSID并绑定sessionId, session记录本次续命时间, 从st中获取referer url或从session中获取referer url进行重定向 - 由于此时
a.com中session已处于登录状态, 浏览器可直接重定向到test1页面中 - 用户访问
b.com/test1,此时b.com中的session未登录, 应用组装ct(client token)并重定向到auth.xyz.cn/getTicket?ct=xxx连接 -
auth.xyz.cn获取ct参数并组装到AuthUserInfo对象, 存储到session中. 此时, 由于session已经登录, 会直接从session中取出AuthUserInfo对象,并从此对象中获取ct参数进行登录行为记录, 生成st(server token)和ticket,缓存ticket和userInfo之间的绑定关系(关系解除是通过redis的expireTime实现).**注意: 此时由于GSID已经和sessionId绑定,因此不需要再次绑定了.**从session中删除AuthUserInfo对象. 从ct中获取callback url,并携带st参数进行重定向 - 后续步骤和上述步骤5,6,7,8类似, 这里不再赘述.
SPA client登录和普通app client登录流程类似, 但需要注意两个问题:
- app front ajax异步调用SSO Server存在跨域调用的问题. 目前我们采用的是nginx CORS(Cross-Origin Resource Sharing)的方式来解决此问题
- 由于ajax请求是可以被手工构造的(这点不同于上面的非SPA请求: 当我们访问
auth.xyz.cn/login,如果session中有ct, 则认为是从其他app过来的认证请求; 如果session中没有ct, 则认为是自身的登录请求), 因此在下图步骤2.1的调用SSO Server登录请求中, 需要加上ct

SSO Server 自身认证流程比较简单. 主要的区别在于它不需要先走getTicket流程让client从server获取一个st, 并通过此st调用getUserInfo流程获取client的userInfo信息.
登录流程图见上述图一的5,6两个流程.

说明: 关键点在于SSO Server logout需在Client logout之前执行. 否则会导致由于消息接收延迟或消息平台异常,出现假登出的情况(client登出而server未及时登出)
SSO Server logout比较简单, 见上图三的流程2
SSO Server Session过期, 需要及时通知各个client执行logout操作. 由于目前SSO Server Session采用的是Redis共享Session的方式.这里, 我们使用了一种小技巧, 通过Redis(2.8+)中的Keyspace Notification的方式来处理session过期的问题.
具体说明如下:
-
Keyspace Notification是在Redis 2.8以上的版本中才有的功能, 因此需要redis升级到此版本以上
-
redis配置文件redis.conf中配置如下条目
notify-keyspace-events "Kx"这样可以通过redis的psubscribe实现对指定key的expire事件监听, 并处理logout流程.
client session和server session是两个不同的session. 如果我们在client session上进行操作而不给server session进行续命, 那么server session在配置的timeout之后就会logout, 并发消息给各个client,导致client也logout.因此, 对client的操作必须要定时给server session续命.
续命流程如下:

从上面的流程中可以看出, 无论是client session还是server session, 都应该配置为共享的方式. 否则对于:
- GSID和Session绑定
- LOGOUT流程
- Server Session过期处理
- Session同步
等问题的处理都会非常的麻烦.