目前,许多行业都要求系统建设时满足单点登录的功能。包括互联网端,像阿里巴巴腾讯这种互联网巨头,因为公司旗下产品众多,需要在用户体系打通的前提下,使C端用户能够在自家产品中实现一次注册,多端登录的效果,提高用户体验。亦或是其他网络,例如政务外网,公安专网,银行专网等,因为业务领域众多,往往由众多公司合力建设,此时同样在用户体系打通的前提下,业主方也希望用户能够一次注册,多端登录。综上,单点登录是软件开发领域实现系统安全以及提升用户体验很重要的环节。
市场上主流的SSO开发方案有Spring Security CAS,Apache Shiro,以及SpringSecurity Oauth2.0。此篇文章,基于Spring Security Oauth2.0讨论SSO的实现方法。
OAuth2.0
OAuth2.0 是一种授权机制,主要包含了4种:
授权码(authorization-code)
隐藏式(implicit)
密码式(password):
客户端凭证(client credentials)
https://www.ruanyifeng.com/blog/2019/04/oauth-grant-types.html
阮一峰的网路日志OAuth2.0的四种方式
上述文章,对OAuth2.0 的四种授权机制都有详细介绍,本文中我们只针对授权码模式和密码式两种比较常用的机制做更深入的讨论。
授权码认证

密码认证

刷新令牌

OAuth 2.0 RFC 6749
https://datatracker.ietf.org/doc/html/rfc6749
上面的描述基本说清了Oauth2.0 的密码认证和授权认证两种认证机制的交互模式。下面从具体的工作流程上分析整体的调用流程。
工作流程
密码认证工作流程

时序图中描述了在浏览器、业务系统、认证服务三者之间,登录令牌的产生流程。以及绿色框中描述后台接口访问业务系统时的鉴权机制。
目前微服务框架和SOA框架流行,可以将上面后台访问接口的整个鉴权机制封装成SDK,集成到各个微服务中,通过后台配置文件配置认证服务的http地址以及client_id、client_secret等参数,在微服务启动时加载,即可达到访问接口时需要token授权的目的。
授权码认证工作流程
授权码认证适用的常见场景。举例,CSDN登录页面中嵌入了QQ的跳转页,点击跳转QQ登录页,输入QQ的账号和密码登录,回跳到CSDN完成登录进入CSDN网站,并获取到了QQ的头像和用户名等基础信息。此场景是互联网产品为了方便用户完成登录或者用户忘记密码常用的单点登录场景。在不同行业领域中,同样也适用。举例,在同一用户体系下,系统A通过集成系统B的认证授权完成跳转登录,并获得系统B的后台接口的支撑也是常见的场景。
下面的时序图描述的是在前后端分离模式下,第三方应用获取认证服务生成的access_token,目的在于通过header中携带access_token完成对业务系统的接口调用。

此种模式下,第三方系统对本业务系统的接口访问一般通过http/https方式获取,也可以通过上面的SDK的方式集成(SDK的底层逻辑也是通过http/https的调用)。
实现方式
sso需要实现的功能

上述登录认证的功能都是从redis token和jwt token两种方式来描述。具体这两种方式实现后效果的优缺点,下面分析:
redis token

jwt token

对比两种token方式:
1)jwt token
优点:
去中心化,便于分布式系统使用;
基本信息可以直接放在token中,name,uid;
功能权限信息可以直接放在token中;
缺点:
令牌一旦下发,不受服务端管控;
无法做强制退出,踢人操作;
2)redis token
优点:
服务端可以主动让token失效;
可以后台利用redis的过期时间设置,主动设置续期操作;
缺点:
中心化;
接口调用都得查询redis,增加查询负载和redis依赖;
对比redis token与jwt token可以发现两者都有各自的优缺点。技术选型上如果更倾向于去中心化的jwt token,为了避免令牌泄露而造成的安全隐患,可以采取jwt非对称加密,过期时间设置短,jwt内部信息只包含uid等方法。jwt最大的优点就是stateless,避免对redis的依赖。如果更倾向于使用redis token,则登录模块需要依赖redis,针对大型网站或者项目,需要部署redis 主从+集群的方式,防止redis崩溃导致系统崩溃。
还有一种声音是觉得将jwt也存入redis,使用jwt的同时也可被服务端管控,其实就摒弃了jwt无状态的特性,本质上和redis token没什么差别了。
至于如何选型,还是需要开发者从实际出发,选择满足业务系统需求的模式进行开发。
原创不易,转载请备注微信公众号--青阳大君




