基于IdentityServer4的OIDC实现单点登录(SSO)原理简析

# 写在前面
IdentityServer4的学习断断续续,兜兜转转,走了不少弯路,也花了不少时间。可能是因为没有阅读源码,也没有特别系统的学习资料,相关文章很多园子里的大佬都有涉及,有系列文章,比如:
晓晨大佬的:https://www.cnblogs.com/stulzq/p/8119928.html
蟋蟀 大佬的:
https://www.cnblogs.com/xishuai/tag/[34]小菜学习编程-IdentityServer4/
李念辉、杨旭大佬均有相关文章,翻翻便可找到,就不一一列举了。
但是,不知大家有没有体会,好像看了很多id4(IdentityServer4,下同)的文章,对:
- oidc究竟是个什么蛤蟆?
- OAuth2.0和OpenId Connect究竟有啥区别?
- id4切确是什么东西?
- id4能干些啥?
- id4为什么这么设计?
- id4各授权流程的区别是啥?
- id4的SSO是基于什么原理?
我还是时不时:

老实说,这些问题我也一懂半懂,还有就是看多了、时间跨度大,有的以为懂了提笔又忘了。这时大佬肯定说:
”谁叫你不去看源码?“
我默默的留下了两行老泪:马上看,马上看。
但是我觉得id4很多新手和我一样都有这困扰,上手门槛确实有的高。诚然看源码是个不错的学习方法,但上来就让新人或使用者看源码,无疑很不利于推广、直接劝退啊,毕竟大部分都是跟我一样的菜逼(对不起拖后腿了)。
对应前面提到的一串问题,我不打算在本文一一解答,我今天着重想聊的是:
id4的SSO是基于什么原理?
写本文的初衷是看到李念辉大佬的https://www.cnblogs.com/linianhui/p/oidc-in-action-sso.html,所以本文算算是读博笔记。
啥是SSO?
SSO,全称Single sign-on :在多个应用系统中,只需要登录一次,就可以访问其他相互信任的应用系统。
比如你登录京东后查看我的订单:https://order.jd.com 然后再去查看购物车https://cart.jd.com/cart.action就不需要重新登录。虽然这里顶级域名一致,但其实单点登录并没有此要求。
单点登录,很容易望文生义,以为单点登录就是限制用户只能在一处登录。
下面我们说说我们我们常用的SSO的常用的实现方式。
SSO--基于Cookie的实现简析
这种方式比较简单,使用也比较广泛。
比如我有两个系统:a.example.com 和 b.example.com,很简单,只需要搞个 passport.example.com 登录成功后往:example.com 这个顶级域写登录成功的cookie就行了。而后不管你是c.example.com还是d.example.com或是+∞.example.com都只需要验证登录的cookie就行,简单方便。
不过这种实现方式有个比较大的缺陷:
不能跨域,不能跨顶级的域。
我不能说我登录成功后往jd.com域名下写cookie吧。还有就是每个业务域名都要做登录cookie的校验逻辑 ,不过这算小问题。
既然存在问题,就解决问题吧(这实在没办法解决发现问题的人啊)
SSO--基于CAS流程实现简析
CAS简介
Central Authentication Service,简称:CAS, 是一个单点登录框架或者说解决方案,开始是由耶鲁大学的一个组织开发,后来归到apereo管理。 同时CAS也是开源的,遵循apache 2.0协议,目前代码放在github上:https://github.com/apereo/cas
打开就惊呆了,看到吧,一堆开源项目在用,这logo闪瞎我的钛合金狗眼了

我们看下github简介:
”CAS是一个企业级的、与语言无光的Web SSO解决方案,同时也尝试整合授权和鉴权的需求。“
既然它是一个解决方案,那我们看看它到底提出了啥。
CAS的方案泳道图分析
CAS SSO标准流程,看图说话吧。
右键可看查原图

我们看看发生了啥:
站点App1
- 用户首次访问web App1,App1发现用户未登录,携带目前访问地址302到CAS Server登录页。
- CAS Server登录页检查登录Session不存在,返回一个登录页面。
- 填写账号,点击登录。
- CAS Server验证账号信息成功,创建一个Ticket Granting Ticket(TGT),这个TGT就是当前登录用户的session key。同时,创建一个service ticket并携带service ticket key,st key 作为参数跳转回App1。
- App1用get发送st key 去CAS Server验证,验证通过后返回登录用户信息。
- App1使用返回的登录用户信息构建当前系统的登录状态,并用一个JSESSIONID标记(JSESSIONID是Apache的默认名),并携带这个JSESSIONID重新访问App1。
- App1验证JSESSIONID,登录成功,展示登录成功页面。
- 第二次访问,验证JSESSIONID,直接访问。
站点App2
- 用户首次访问web App2,App2发现用户未登录,携带目前访问地址302到CAS Server登录页。
- CAS Server登录页携带有App1生成的TGT,那么直接做TCT的验证,验证成功不需要登录,创建一个App2的st key,302回App2。
- 后续和以上的5,6,7,8 补逻辑相同,不赘述。
CAS的流程大概于此,实际的实现可能会复杂一点,可能会遇到各式各样的问题。但有理论支撑,总体实现起来还是简单,可靠有保证的。
下面说说基于Id4的OIDC是怎么做单点登录的。
SSO--基于Id4的OIDC实现简析
先准备环境
把官方samples下下来:https://github.com/IdentityServer/IdentityServer4/tree/master/samples
我删掉了其他项目,剩下这两个,一目了然:

分别把这两个站点部署为:
我们再看一眼Idoc服务端配置:

配置IdentityServer,Configs添加这么一个客户端:
// sso implicit client
new Client
{
ClientId = "ssoimplicit", //这个client id 跟 MfcImplicit 里面的配置要一致
ClientName = "sso implicit clinet",
AllowedGrantTypes = GrantTypes.Implicit,
RedirectUris = { "http://sso.client.net/signin-oidc" },
PostLogoutRedirectUris = { "http://sso.client.net/signout-callback-oidc" },
AllowedScopes = new List<string>
{
IdentityServerConstants.StandardScopes.OpenId,
IdentityServerConstants.StandardScopes.Profile,
IdentityServerConstants.StandardScopes.Email
}
}
ok,我们用下抓包工具观察下登录流程。
1、受保护客户端页面的访问
sso.client.net是客户端,而登录页在sso.client.net服务端
我们先打开需要登录才可以访问的:http://sso.client.net/Home/Secure

这里302到了授权端点 http://odic.server.net/connect/authorize
2、授权端点对客户端请求的验证
这就是步骤1中, 302挑战的授权端点携带的参数。

我们先看看这些参数
client_id:ssoimplicit //我们前面配置的clinenid=
reponse_mode:form_post //指示oidc服务器返回数据的形式是form表单
response_type:id_token //区别于oauth2授权请求的一点,必须包含有id_token这一项。
scope:openid profile //区别于oauth2授权请求的一点,必须包含有openid这一项。
state:oauth2定义的一个状态字符串,这里的实现是加密保存了一些客户端的信息,让你最后可以在登录成功后带回到客户端,这个参数听重要的
nonce:上一步中写入cookie的值,这字符串将来会包含在idtoken中原样返回给客户端,做安全校验用。
redirect_uri:http://sso.client.net/signin-oidc //认证成功后的回调地址,就是我们配置里面的
授权端点有很多功能,这里主要做了两件事:
- 先判断待过来的参数是否合法,比如clientid是不是配置里面的,参数有没有按要求、规范传过来,参数是否被篡改,未验证通过会报错。
- 授权与否的校验,根据携带的参数,判断如果登录,就直接回调 redirect_uri参数地址:http://sso.client.net/signin-oidc,否,302到登录页,引导用户登录。
3、登录
初次登录,步骤2中的授权端点判断当前未登录,还是302,跳转登录页,引导用户登录授权。

点击登录,跳转到是否授权页面,这个页面不一定展示,可通过配置Client的RequireConsent=false,跳过这个页面。

of course Yes!
4、登录成功,客户端构建登录状态
我们看看点Yes Alow 之后的请求。

可以清楚的看到去到了:
http://odic.server.net/connect/authorize/callback
callback,哦,这是一个登录回调,它干了啥呢,我们仔细看响应:

哦,它这里响应回了一个页面,这个页面只有一个表单,当页面一加载完成立刻post表单到:action='http://sso.client.net/signin-oidc' 这个地址。并且仔细看看表单的参数,前面的那些scope、state啊这些参数全都带了过来,有意思,没错,这精妙的设计也是规范之一。
这里它为什么不带上clientid呢?哈哈,客户端自己肯定知道自己的clientid的,另外,还有中间这一大串的id_token你忘了吗,这里面可是可以携带信息的哦。
来,我们看看这个id_token究竟是何方妖孽。

我们看到id_token带有登录用户的信息:
iss:token发放的服务器地址
aud:clientid
sid:会话信息
kid:当前token的标识符
name:用户名
此外还有比如id_token的发放时间,过期时间,nonce,用户非机密信息等等。还有蓝色部分需要使用客户端公钥验证的签名等等。
这个时候客户端已经拿到登录用户的信息了,这时客户端直接使用登录用户信息,构建当前应用sso.client.net的登录状态即可。
比如下面的这个 Set名为Implicit的Cookie:

这个Cookie是可以删掉的,它本身只维持了在sso.client.net的登录状态而已,如果你删掉它,它就会重新跑到授权端点:http://odic.server.net/connect/authorize 去验证一下,发现当前会话还是处于登录状态的,然后又302到登录回调地址http://sso.client.net/signin-oidc,然后/signin-oidc从state参数里面取出redirect_url,302回到当前页面。
最后我们来看一下登录成功的页面

单点登出
单点登出我就不细说了,使用:
//指定登录方案的方式登出
await HttpContext.SignOutAsync(IdentityServerConstants.DefaultCookieAuthenticationScheme);
//或者直接
await HttpContext.SignOutAsync();
暴力点删除cookie也可以,不过那只能算是半退出状态吧。
总结
通过对以上一个使用Id4构建的OIDC实现的登录流程来看,OIDC的SSO它完全无光域名的,id4登录成功后,客户端通过使用id_token来构建自身的登录状态,一个client如此,N个皆然。
大家好像感觉这个SSO的实现方式跟前面的CAS流程很像诶,我们再看一遍前面CAS的图

好像是发现了啥不得了的东西。
没错:openid也是基于CAS流程的一个实现(我根据理解猜的 没有证据)。
再多说两句
id4确实是好东西,暂时用不上也要多了解、学习,最好写个博客做个笔记加深下理解。
在理解的基础上不要去背各种Flow有啥区别什么的,知道什么场景下用那种流程就行,也没几个。
善用官方文档、Sample。
本文示例源码
https://github.com/gebiWangshushu/cnblogs-demos
参考
https://yq.aliyun.com/articles/636281
https://www.cnblogs.com/linianhui/p/oidc-in-action-sso.html
基于IdentityServer4的OIDC实现单点登录(SSO)原理简析的更多相关文章
- Asp.Net Core基于Cookie实现同域单点登录(SSO)
在同一个域名下有很多子系统 如:a.giant.com b.giant.com c.giant.com等 但是这些系统都是giant.com这个子域. 这样的情况就可以在不引用其它框架的情况下, ...
- 单点登录SSO原理
最近接触了一点单点登录的知识,有一点理解,记录一下.有些问题并没有找到完美的解决方法,还需要找点已有框架来看看. 欢迎留言探讨. 1 概念 1.1 概念及理解 有一个网上广为流传的 ...
- 浅析C#中单点登录的原理和使用
什么是单点登录?我想肯定有一部分人"望文生义"的认为一个用户只能在一处登录.其实这是错误的理解(我记得我第一次也是这么理解的).单点登录指的是多个子系统只需要登录一个,其他系统不需 ...
- IdentityServer4之SSO(基于OAuth2.0、OIDC)单点登录、登出
IdentityServer4之SSO(基于OAuth2.0.OIDC)单点登录.登出 准备 五个Web站点: 1.localhost:5000 : 认证服务器.2 ...
- 基于云端的通用权限管理系统,SAAS服务,基于SAAS的权限管理,基于SAAS的单点登录SSO,企业单点登录,企业系统监控,企业授权认证中心
基于云端的通用权限管理系统 SAAS服务 基于SAAS的权限管理 基于SAAS的单点登录SSO 基于.Net的SSO,单点登录系统,提供SAAS服务 基于Extjs 4.2 的企业信息管理系统 基于E ...
- Windows Azure 安全最佳实践 - 第 5 部分:基于Claim 的标识,单点登录
基于Claim的身份标识是处理网站与 Web 服务的身份认证和访问一种简单而强大的方式,无论您是在本地工作还是面向云工作.您可以通过减少自定义实施和使用基于Claim的单一简化标识模型,创建更安全的应 ...
- Redis缓存实现单点登录SSO
.NET基于Redis缓存实现单点登录SSO的解决方案 .NET基于Redis缓存实现单点登录SSO的解决方案 一.基本概念 最近公司的多个业务系统要统一整合使用同一个登录,这就是我们耳熟能详的单 ...
- 单点登录SSO:可一键运行的完整代码
单点登录方案不同于一个普通站点,它的部署比较繁琐:涉及到好几个站点,要改host.安装证书.配置HTTPS. 看到的不少这方面示例都是基于HTTP的,不认同这种简化: 1. 它体现不出混合HTTP/H ...
- 单点登录SSO:图示和讲解
目录 概述 示例运行效果动画 跨域Web SSO时序图 代码截图 几个基本概念 涉及的站点和页面 重点理解:单点登录的核心步骤 敢说最准确的单点登录图示,因为: 我严格对照所画时序图的每个步骤,开发了 ...
随机推荐
- Android零基础入门第41节:使用SimpleAdapter
原文:Android零基础入门第41节:使用SimpleAdapter 通过ArrayAdapter实现Adapter虽然简单.易用,但ArrayAdapter的功能比较有限,它的每个列表项只能给一个 ...
- Fundamentals Code Library,包含HTTP TCP JSON BigInteger 加密算法 Unicode等许多东西
http://fundementals.sourceforge.net/index.html https://github.com/fundamentalslib/fundamentals5 http ...
- FMX有两种消息处理的实现方式,一种是用TMessageManager来实现自定义的消息,另外一种象TEdit中的实现,直接声明消息方法(firemonkey messaging)
看FMX代码,发现有两种消息处理的实现方式,一种是用TMessageManager来实现自定义的消息,另外一种象TEdit中的实现,直接声明消息方法. 早前,看过文章说TMessageManage ...
- libjingler-0.6.2在windows和ubuntu 10.04下的编译(Google Talk)
Libjingle版本:0.6.2 所需的资源: gtest-1.6.0.zip http://download.csdn.net/detail/cl_gamer/48 ...
- 测试链接服务器sql 语句
sp_addlinkedsrvlogin 创建或更新本地 Microsoft® SQL Server™ 实例上的登录与链接服务器上远程登录之间的映射. 语法 sp_addlinkedsrvlogin ...
- pip升级到18.0版本过程中报错解决方法
我这台电脑是windows10系统,一般在cmd命令行界面下执行pip的升级命令:pip install –upgrade pip 安装的时候,会有拒绝访问报错:这个时候应该是权限的问题,于是在win ...
- MySQL如何转SQL server
MySql的数据如何导入到Sql Server数据库中?(转载) 本文咱讨论的重点是如何将MySql数据导入到Sql Server数据库中,所以就需要机器上同时安装了MySql和Sql Serve ...
- 最全java多线程总结2--如何进行线程同步
上篇对线程的一些基础知识做了总结,本篇来对多线程编程中最重要,也是最麻烦的一个部分--同步,来做个总结. 创建线程并不难,难的是如何让多个线程能够良好的协作运行,大部分需要多线程处理的事情都不 ...
- 视频编解码的理论和实践2:Ffmpeg视频编解码
近几年,视频编解码技术在理论及应用方面都取得了重大的进展,越来越多的人想要了解编解码技术.因此,网易云信研发工程师为大家进行了归纳梳理,从理论及实践两个方面简单介绍视频编解码技术. 相关阅读推荐 &l ...
- java的equals与==的区别
看了网上关于equal与==的区别,感觉很多有些片面,不仔细,这里我来说说我对equal与==的理解 首先要了解基本类型与引用类型 1.int,char,boolean之类的就是基本类型,我们只要使用 ...