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



# 写在前面

IdentityServer4的学习断断续续,兜兜转转,走了不少弯路,也花了不少时间。可能是因为没有阅读源码,也没有特别系统的学习资料,相关文章很多园子里的大佬都有涉及,有系列文章,比如:

晓晨大佬的:

https://www.cnblogs.com/stulzq/p/8119928.html

蟋蟀 大佬的:
https://www.cnblogs.com/xishuai/tag/[34]%E5%B0%8F%E8%8F%9C%E5%AD%A6%E4%B9%A0%E7%BC%96%E7%A8%8B-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

  1. 用户首次访问web App1,App1发现用户未登录,携带目前访问地址302到CAS Server登录页。

  2. CAS Server登录页检查登录Session不存在,返回一个登录页面。

  3. 填写账号,点击登录。

  4. CAS Server验证账号信息成功,创建一个Ticket Granting Ticket(TGT),这个TGT就是当前登录用户的session key。同时,创建一个service ticket并携带service ticket key,st key 作为参数跳转回App1。

  5. App1用get发送st key 去CAS Server验证,验证通过后返回登录用户信息。

  6. App1使用返回的登录用户信息构建当前系统的登录状态,并用一个JSESSIONID标记(JSESSIONID是Apache的默认名),并携带这个JSESSIONID重新访问App1。

  7. App1验证JSESSIONID,登录成功,展示登录成功页面。

  8. 第二次访问,验证JSESSIONID,直接访问。

站点App2

  1. 用户首次访问web App2,App2发现用户未登录,携带目前访问地址302到CAS Server登录页。

  2. CAS Server登录页携带有App1生成的TGT,那么直接做TCT的验证,验证成功不需要登录,创建一个App2的st key,302回App2。

  3. 后续和以上的5,6,7,8 补逻辑相同,不赘述。

CAS的流程大概于此,实际的实现可能会复杂一点,可能会遇到各式各样的问题。但有理论支撑,总体实现起来还是简单,可靠有保证的。

下面说说基于Id4的OIDC是怎么做单点登录的。

SSO—基于Id4的OIDC实现简析

先准备环境

把官方samples下下来:https://github.com/IdentityServer/IdentityServer4/tree/master/samples

我删掉了其他项目,剩下这两个,一目了然:

分别把这两个站点部署为:

http://odic.server.net

http://sso.client.net

我们再看一眼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 //认证成功后的回调地址,就是我们配置里面的

授权端点有很多功能,这里主要做了两件事:

  1. 先判断待过来的参数是否合法,比如clientid是不是配置里面的,参数有没有按要求、规范传过来,参数是否被篡改,未验证通过会报错。

  2. 授权与否的校验,根据携带的参数,判断如果登录,就直接回调 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

文章博客园地址请点击“阅读原文”

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/308127.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

fc协议有哪些数据传输服务器,FC协议详解

FC协议简介开发于1988年&#xff0c;最早是用来提高硬盘协议的传输带宽&#xff0c;侧重于数据的快速、高效、可靠传输。到上世纪90年代末&#xff0c;FCSAN开始得到大规模的广泛应用。FC协议其实并不能翻译成光纤协议&#xff0c;只是FC协议普遍采用光纤作为传输线缆而不是铜缆…

51. N 皇后018(回溯法求解)

一&#xff1a;题目 二:思路 思路: 1.这里在选择建树(也就是在选择解的空间上)是 子集树 2.那么在结点上我们选择的是一个二维的矩阵就是将最后的结果落实到一个二维容器里 也就遍历到叶节点时候一种可行解的情况 3.写码思路&#xff1a; <1>:递归函数的参数: backtacki…

小姐姐为你解析马爸爸是怎么用大数据“宰你”的

一、首先大数据杀熟是什么&#xff1f;大数据杀熟本质就是一种数据营销手段&#xff1a;商家为了追求商业目的&#xff0c;利用交易双方信息的不对称性&#xff0c;根据每个用户的身份信息和历史数据表现&#xff0c;或者根据用户当前的需求来调整产品定价的手段 &#xff1b;比…

苹果手机上没有显示订阅服务器,手机里没有订阅的选项,我该怎样取消自动收费项目...

有些应用和服务会在用户订阅后提供内容访问权限。与购买单个项目(例如宝石和金币等游戏币)不同&#xff0c;在您选择结束订阅之前&#xff0c;订阅会自动续订。自动续订的订阅包括&#xff1a;Apple Music 订阅Apple 新闻、报纸和杂志订阅内容或服务的 App 内订阅(HBO NOW、Spo…

7-4 N皇后 (28 分)(思路+详解)

一&#xff1a;题目 Come 宝&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01;&#xff01; 在N*N的方格棋盘放置了N个皇后&#xff0c;使得它们不相互攻击&#xff08;即任意2个皇后不…

内存不够用还要速度快,终于找到可以基于 File 的 Cache 了

一&#xff1a;背景1. 讲故事18年的时候在做纯内存项目的过程中遇到了这么一个问题&#xff0c;因为一些核心数据都是飘在内存中&#xff0c;所以内存空间对我们来说额外宝贵&#xff0c;但偏偏项目中有些数据需要缓存&#xff0c;比如说需要下钻的报表上的点&#xff0c;基于性…

计算机网络:如何传输一条数据(详解)

一&#xff1a;不同的localhost如何传送信息 1:图示概览图 (1):无注解 (2):有注解 这里我在这个线路层中又连了一些新的 sw 和 router 其实还可以连更多&#xff0c;相当于一个网状的 注意同一个网络中只有一个网关&#xff0c;形象点理解网关就是通往别的网洛的大门 在下方…

为什么我们需要Logstash,Fluentd等日志摄取器?

前文传送门&#xff1a;如何利用NLog输出结构化日志&#xff0c;并在Kibana优雅分析日志&#xff1f;疑问&#xff1a;既然应用能直接向ElasticSearch写日志&#xff0c;为什么我们还需要Logstash,Fluentd等日志摄取器&#xff1f;而且这些日志摄取器组件还成为日志收集的事实标…

7-1 装载问题 (10 分)(思路+详解)

一&#xff1a;题目 Come 宝宝&#xff01;&#xff01; 输出格式: 输出所有可行的方案数量 输入样例1: 3 50 50 10 40 40结尾无空行 输出样例1: 4结尾无空行 输入样例2: 3 50 50 20 40 40结尾无空行 输出样例2: 0二:思路 1.这个解的空间选择的是子集树 2.递归函数参数 b…

程序员是终身学习的职业,应该怎么学习?

在上一篇《一款用了就不想走的工具》中介绍了一款工具 Notion &#xff0c;可以做学习的规划、时间的管理、学习的记录等&#xff0c;但学习本身还是需要一些方法的&#xff0c;本文谈谈我对学习的一些感悟。不管你是刚刚进入职场的新人&#xff0c;还是工作多年的老兵&#xf…

7-2 批处理作业调度 (10 分)(思路+详解)

一&#xff1a;题目:宝宝 你要永远开心&#xff0c;下雪了&#xff0c;多穿点&#xff0c; 输入格式: 第一行输入作业个数n。 第二行输入各任务在机器一上的完成时间。 第三行输入各任务在机器二上的完成时间。 输出格式: 最短完成时间和 输入样例: 3 2 3 2 1 1 3结尾无空…

WindowsSdkDir 从何处来?

缘起 我在《修复被破坏的 vs 工程设置》和《修复被破坏的 vs 工程设置&#xff08;续&#xff09;》这两篇文章中&#xff0c;分享了调查 VS 包含路径错误的问题&#xff0c;感兴趣的小伙伴儿可以查看。依稀记得在 2013 年的时候调查过类似的问题。前一阵子没翻到&#xff0c;这…

7-3 符号三角形 (10 分)(思路+详解)

一&#xff1a;题目 Come 宝 &#xff01;&#xff01;&#xff01; 输入格式: 第一行符号个数n 输出格式: 符合要求的三角形个数 输入样例: 4结尾无空行 输出样例: 6二:思路 思路: 1.如果我们确立的第一行的符号是什么 &#xff0c;那么我们就可以基本上确定我们的符号三…

7-1 内存分区分配--首次适应算法 (100 分)

一&#xff1a;题目7-1 内存分区分配–首次适应算法 (100 分) 宝 今天你看我博客了吗 输入内存的大小和阈值minsize&#xff0c;按照首次适应算法进行连续的分区分配。在划分时&#xff0c;若剩余的内存小于等于minsize&#xff0c;则将整块内存分配给该进程不再进行划分。 根…

如何在生产环境下用好EFCore

原文链接&#xff1a;https://www.thereformedprogrammer.net/handling-entity-framework-core-database-migrations-in-production-part-2/作者&#xff1a;Jon P Smith在生产中运用EFCore的模式实战这是使用EF Core迁移数据库的系列文章中的第二篇。本文着眼于将迁移应用于数…

39. 组合总和020(思路+详解)

一&#xff1a;题目&#xff1a; 给定一个无重复元素的正整数数组 candidates 和一个正整数 target &#xff0c;找出 candidates 中所有可以使数字和为目标数 target 的唯一组合。 candidates 中的数字可以无限制重复被选取。如果至少一个所选数字数量不同&#xff0c;则两种…

8种方法解决vue创建项目报错:command failed: npm install --loglevel error

8种方法解决vue项目创建失败问题1、重建项目2、清除缓存3、重装淘宝源4、修改useTaobaoRegistry5、重装node6、删除npmrc文件7、 node版本问题8、css编辑工具选择9、管理员身份运行踩了这个巨大的坑&#xff01;&#xff01; 试了一个晚上终于找到了创建项目成功了T_T 当报错了…

40. 组合总和 II021(回溯法)

一&#xff1a;题目 给定一个数组 candidates 和一个目标数 target &#xff0c;找出 candidates 中所有可以使数字和为 target 的组合。 candidates 中的每个数字在每个组合中只能使用一次。 注意&#xff1a;解集不能包含重复的组合。 示例 1:输入: candidates [10,1,2,…

.NET Core + Kubernetes:Helm

Helm[1] 作为 Kubernetes 体系的包管理工具&#xff0c;已经逐渐成为了应用分发标准&#xff0c;在 .NET 开发中&#xff0c;可以理解为与 NuGet 包类似。回顾之前文章中的介绍&#xff0c;Kubernetes 中单个服务的部署有时会涉及到多种资源类型&#xff0c;如&#xff1a;Depl…

vue项目中引入阿里图标iconfont

vue如何在创建好的项目中引入阿里图标iconfont呢&#xff0c;涉及到以下几个步骤&#xff1a; 1、首先先到阿里图标官方网站https://www.iconfont.cn/&#xff0c;先对账户进行登录&#xff0c;登录完成后任意选择几个图标加入购物车 2、加入购物车后&#xff0c;点击页面最右…