前言
最近在对基于token做身份认证的项目中扩展sso。
背景
项目大致架构如下
其中服务器端是RESTful风格的API服务器,客户端基于Vue开发的SPA。身份认证是基于token,客户端登录之后,服务器端验证并发送JWT token给客户端,客户端将token存入localStorage中并每次恢复到Vuex中,客户端每次请求都会在HTTP自定义头部中附带token。
本文简述下我对OIDC解决方案的简单理解以及基于上述架构实现sso的思路。
正文
OIDC的官方解释如下
OpenID Connect 1.0 is a simple identity layer on top of the OAuth 2.0 protocol. It allows Clients to verify the identity of the End-User based on the authentication performed by an Authorization Server, as well as to obtain basic profile information about the End-User in an interoperable and REST-like manner.
也就是OAuth2.0只解决了资源的访问和分享,OIDC则基于此实现了用户的认证。它的主要目的是提供一次登录,多个站点享有登录状态。也就是当用户在某一使用OIDC的网站登录时,用户被重定向到OpenID站点登录,然后重定向回原来网站。
OIDC已经有很多的企业在使用,比如Google的账号认证授权体系,Microsoft的账号体系也部署了OIDC,当然这些企业有的也是OIDC背后的推动者。
OAuth2提供了Access Token来解决授权第三方客户端访问受保护资源的问题;相似的,OIDC在这个基础上提供了ID Token来解决第三方客户端标识用户身份认证的问题。OIDC的核心在于在OAuth2的授权流程中,一并提供用户的身份认证信息(ID-Token)给到第三方客户端,ID-Token使用JWT格式来包装,得益于JWT(JSON Web Token)的自包含性,紧凑性以及防篡改机制,使得ID-Token可以安全的传递给第三方客户端程序并且容易被验证。应用服务器,在验证ID-Token正确之后,使用Access-Token向接口换取用户的更多的信息。
OIDC到底怎么运行的
第一期先从简,也不讨论什么OIDC协议族,就单单说一下OIDC是怎么运作的。以还是以午安网举例。
如果我要使用大午安账号登入午安空间网站,那么这个大致流程如下:
使用Implicit Flow- 首先午安空间会发送授权请求给oidc-server
- 如果已经登录了,oidc-server会返回一个“证件”或者如果你没登录会要求你登录,然后询问你是否授权给午安空间某些权限比如邮件地址等(当然午安这个例子里面不存在,因为肯定都是全权限)。
- 一旦你确定并授权了这次登录,oidc-server会发送Acess-Token和ID Token(如果要求了),并跳转回午安空间网站。(可以通过url附带)
- (认证) 午安空间网站获得ID-Token之后,使用oidc-server提供的公钥解密验证。
- 然后午安空间就可以通过之前得到的Access-Token去访问oidc-server获取用户信息了
午安网实现SSO的全流程设计
设计可能比较粗糙或者有问题,如果有问题希望评论一下帮我修正修正。 设计使用的是Implicit Flow。
单点登录
主动登出
没啥好说的,客户端清理自己的状态,然后发出登出请求给oidc-server。
被动登出
这块就找到了一个网上的例子
其利用oipc协议族里的Discovery服务中提供的一个check_session_iframe接口。
核心原理是让客户端插入一个oidc-server页面的iframe并周期性的检查,当我在“午安空间”点击登出的时候,会发出登出请求给oidc-server并触发oidc-server的站点清理自己的cookie,然后在之前客户端中使用check_session_iframe这个隐藏的iframe可以检测到这种变化,从而使得客户端可以得知用户已在再其他的应用的客户端退出登录,这时候就清理自己客户端的登录状态。
例子中的客户端代码
后记
这部分放的是下版本要加的或者完善的。
了解下Authorization Code Flow。
自动登录补充
如果只有上面的解决方案的话会存在一个问题,那就是如果我sso已登录,我到另一个网站比如午安影视,我需要点击登入之后才会出现登录状态。也就是说没有自动登录。
一个实现的方法是可以在一开始就去访问oidc-server询问是否已经登录,oidc-server的协议族Discovery提供一个接口。