网站首页 > 技术文章 正文
先说下本次.NET网站应用与CAS认证集成的特点
- CAS-服务器端默认是已经搭建完毕,且正常运行的,本次方案只针对CAS客户端如何集成介绍。
- 无需CAS源码,也无需深层研究CAS服务器端原理,不需要进行繁琐的配置文件修改调整。
- 保留应用内部用户信息存储和验证方式不变,如form认证等可以继续保留。
- 对应用无需进行任何架构和功能调整,只需要对原登录页面简单新增几行代码即可。
- 本次方案介绍一个CAS客户端如何与CAS认证集成,最主要是介绍2个或多个CAS客户端同时与CAS做集成。
- 本次集成方案是基于.NET环境通过C#语音中进行的代码示例,同样的逻辑在其他Web应用如JAVA、PHP等语言下是一样通用的。
- 由于是与多个系统同时做集成,暂时没有考虑如何登出注销的问题,用户浏览器关闭后,存储的用户信息自动消失。
事情起因是最近公司有个项目需要与CAS认证系统做单点集成,CAS服务器端用户已经搭建完成。公司之前做过类似的单点集成,但是没有直接与CAS做认证的,对CAS这块不是很熟悉。所以一开始不打算做了,但是甲方一直要求做,然后给CAS的供应商要了接口文档和说明,本来以为接口会很详细明了,谁知道给的文档都是如何部署JAVA服务器端的文档。不懂JAVA,看文档简直是隔行如隔山,关键文档是如何部署服务器端的,不是介绍第三方应用如何与CAS认证集成的。没办法,最终这个CAS认证我说还是我自己尝试下吧。
然后就开始了百度、CSDN的苦逼搜索之路。网上一搜".NET集成CAS认证",搜索结果一大片,都有各种介绍和各种原理说明,其中大部分都是需要下载.net版本的 CAS源码进行二次改造集成等等。
一看有源码,好啊!抓紧下载源码,先是下载了最新.NET版本CAS源码,但是在开发环境无法打开,花费了不少时间解决这个问题,最终看到有个文章里面说最新的需要VS2017才能打开,然后又下载了一个适配VS2013版本的源码。
OK,这次可以打开正常调试了,很开心,觉得离成功越来越近了。然后按照介绍进行配置、调试,发布到IIS进行测试。好吧,然后我才发现我掉入到坑里面了。调试到各种问题,如重复定向问题、再次验证失败问题。花了3天时间把整个源码逻辑一步步的跟踪了很多遍,弄懂了大部分代码的功能,但悲哀的是最终要实现的单点效果一直没实现。
然后就继续网上找资源,突然一个简单的代码示例出现在我的眼前
string CASHOST = "https://cas.test11.cn/cas/"; //cas服务器地址
string tkt = Request.QueryString["ticket"];
string service = Request.Url.GetLeftPart(UriPartial.Path);
if (tkt == null || tkt.Length == 0) //检查未带ticket,重定向到cas登录页
{
string redir = CASHOST + "login?service=" + service;
Response.Redirect(redir);
return;
}
string validateurl = CASHOST + "serviceValidate?ticket=" + tkt + "&service=" + service;
StreamReader Reader = new StreamReader(new WebClient().OpenRead(validateurl)); //根据ticket验证取回用户信息
string resp = Reader.ReadToEnd();
NameTable nt = new NameTable();
XmlNamespaceManager nsmgr = new XmlNamespaceManager(nt);
XmlParserContext context = new XmlParserContext(null, nsmgr, null, XmlSpace.None);
XmlTextReader reader = new XmlTextReader(resp, XmlNodeType.Element, context);
string netid = null;
while (reader.Read()) //从返回信息中读取用户账号等
{
if (reader.IsStartElement())
{
string tag = reader.LocalName;
if (tag == "user")
netid = reader.ReadString();
//这里可以读取其它返回信息
}
}
reader.Close();
if (netid == null) //服务器拒绝验证,未返回用户信息
{
Response.Write("CAS returned to this application, but then refused to validate your identity.");
}
else //返回了用户信息,做初始化成功登录本软件处理
{
Session["UserName"] = netid;
Response.Write("Welcome " + netid);
//此处添加应用内部原有登录逻辑。即可登录成功
}
看到这块代码后感觉豁然开朗,然后迫不及待的进行了尝试。将CAS服务器地址改为用户提供的测试地址,然后将以上代码加入到现在项目的登录页面后台,调试后一切OK。输入应用系统的登录地址后,可以直接跳转到CAS登录页面,输入用户名密码后即可正常跳转回应用系统自己的首页。
以上代码的具体逻辑,相信大部分人都可以看明白,CAS认证的详细原理这里就不再赘述了,网上有很多介绍。这里只简单介绍下上面的认证过程,即一个CAS-Client如何与CAS-Server做集成。
暂以“Client1”代替CAS-Client。”Client1“与CAS认证的核心是ticket生成以及如何根据ticket获取对应的用户信息,只要明白了以上两点,即可很快明白CAS认证的基本原理。
· Ticket如何生成的? Ticket是用户终端请求CAS-Server端登录成功后(情形一)或TGC验证通过后(情形二)由CAS-Server生成的。
· 如何根据Ticket获取对应的用户信息?需要带上票据Ticket和客户端地址service,去访问CAS-Server的serviceValidate接口进行数据获取,完整请求示例为:【https://castest.cn/cas/serviceValidate?ticket=STSx6eyvj7cPPCfn0pMZ&service=https://Client1/iPortal/Login_admin.aspx】。获取到返回数据后,返回数据格式为XML,解析其中的user节点,即为用户账号。
情形一:【一个CAS-Client与CAS-Server认证集成过程】
下面介绍具体认证过程:
1)终端第一次访问Client1
- 首先,检测本地没有缓存Client1的用户信息;
- 然后,检测到请求信息中没有Ticket凭据(即CAS为用户签发的访问某一服务票据);
- 所以,Client1将请求重定向到CAS—Server(https://cas.test.cn/cas/login),并传递 Service (也就是要访问的系统A的登录页URL,以便登录成功过后转回该地址)示例【https://cas.test.cn/cas/login? Service =https://Client1/iPortal/Login_admin.aspx】
2)终端第一次访问CAS—Server
- CAS—Server检测到请求信息中没有TGC(即CAS登录成功后在客户端存储的用户信息),所以跳转到自己的登录页;
- 终端输入用户名、密码,点击登录按钮,认证成功后,CAS—Server会生成一个服务票据—Ticket与CAS会话标识—TGC。大家只需要知道Ticket即可,上面有介绍。
- 然后,CAS—Server会将Ticket加在url 后面,将请求redirect 回客户web 应用,例如URL为【https://Client1/iPortal/Login_admin.aspx?ticket=ST-5-Sx6eyvj7cPPCfn0pMZ】
3)终端携带ticket再次请求Client1
注:本次请求是通过CAS登录页面登录成功后,由CAS服务器端重定向跳转到的Client1。不属于、也不需要用户主动操作。
- 这时Client1后台系统看到ticket 参数后,会获取此参数,由其后面的“票据验证”功能进行逻辑处理,不再继续往CAS服务器端进行跳转。
- Client1“票据验证”功能实现逻辑为:通过http请求,访问cas 服务的/serviceValidate 接口,将ticket 、service 都传到此接口,由此接口验证ticket 的有效性并返回用户数据。请求接口示例为【https://cas.test.cn/cas/serviceValidate?ticket=ST0pMZ&service=https://Client1/iPortal/Login_admin.aspx】
- CAS的serviceValidate 接口验证成功后,会返回用户账号信息,Client1在此获取到用户账号,然后把用户账号转为Client1应用内部的Cookie或者Session用户凭据。
- 至此为止,SSO 会话就建立起来了。Client1登录成功。
情形一的原理大家应该都可以看明白吧,也即代码主要实现的功能。如果明白了上面那些逻辑,恭喜你,CAS认证你已经学会了一半,为什么是一半呢?
因为上面的整个过程是Client1直接与CAS-Server端做的认证,同时也是第一次登录认证,是在CAS登录页成功后获取到ticket后进行的操作。那假如Client1系统已经与CAS认证成功了,现在有个Client2系统也需要与CAS做认证集成,如何在Client2中获取到CAS已经认证成功的用户信息呢?即下面介绍的【多个CAS-Client与CAS-Server认证集成过程】
情形二:【多个CAS-Client与CAS-Server认证集成过程】
因为Client1获取得用户账号是在CAS登录页面登录成功后又根据跳转回传的ticket获取的,再访问Client2时不应该再出现登录页面了,那如何获取ticket呢?既然获取不到ticket你是不是会想到有没有其他方式可以可以获取到已经认证的CAS用户信息呢?
好吧,我就掉入到这么一个新的坑里面去了,想着去CAS源码里面查下有没有其他方式获取客户端已经认证的用户信息。然后又花了几天时间继续去调试CAS源码,一步步跟踪,一步步查看方法定义。不过让人遗憾的是,不知道是我的代码能力有问题,还是因为英文水平太差,或者是下载的CAS源码版本太久,最终都以失败告终。在CAS源码里面没有查询到任何有帮助的代码,我只是想知道如何判断当前客户端已经完成了与CAS的认证、同时获取到用户账号,有这么难吗?后来真的都要放弃了。
然后,我也不知道是什么原因,或者是说灵光一闪也好,还是我天赋异禀也好,哈哈,我突然又把目光转向了上面那段代码。抱着试试看的心态模拟了一下:首先登录Client1系统,会出现CAS登录页面,登录成功后会进入Client1的首页,然后再登录Client2(与Client1集成CAS的代码完全一样)系统。
哇塞,让人意想不到的事发生了,Client2系统竟然不需要再次登录,直接进入了系统首页,Client2也直接与CAS认证成功,太神奇了。
这说明了什么?然后我又反复去梳理上面代码示例的逻辑。最终确定了一个事实,过程如下:
- 当Client1与CAS认证成功后,此时已经在客户端生产了CAS的用户凭据信息。
- 如果此时Client2系统第一次去请求CAS的登录页,地址示例为【https://cas.test.cn/cas/login? Service =https://Client2/iPortal/Login_admin.aspx】。CAS服务器端可以检测到当前客户端环境中存在CAS的用户凭据信息
- 然后CAS服务器端不会将当前页面请求转到CAS的登录页,而是会跳过这一步骤,同时生成有效的ticket,携带ticket直接跳转到Client2的登录页。最终跳转地址如下:【https://Client2/iPortal/Login_admin.aspx?ticket=ST-5-Sx6eyvj7cPPCfn0pMZ】
- 后面的过程就和“情形一:3)终端携带ticket再次请求Client1”中描述的完全一致了。这样就实现了多个系统直接与CAS认证集成,实现了多个系统的免登陆。
至此,多个CAS-Client与CAS-Server认证集成过程已经顺利完成。
看到这里,大家是不是有豁然开朗的感觉?真是踏破铁鞋无觅处,得来全不费功夫。没想到被CAS源码折磨的死去活来的时候,上面那一段小小的代码竟然能实现全部功能。在这次研究摸索的过程中,也理解了一种新的SSO单点思路。希望能和大家一起功能进步。
猜你喜欢
- 2024-10-01 单点登录终极方案之 CAS 应用及原理
- 2024-10-01 Spring Boot+CAS 单点登录,如何对接数据库?
- 2024-10-01 cas单点登录服务器连接数据库 cas单点登出
- 2024-10-01 shiro集成spring使用cas单点登录配置
- 2024-10-01 聊聊单点登录(SSO)中的CAS认证,看完秒懂!
- 2024-10-01 单点登录(SSO)解决方案介绍 单点登录实现流程
- 2024-10-01 Java实现SSO单点登录 java单点登录解决方案
- 2024-10-01 Spring Security 项目模块及依赖项详解
- 2024-10-01 基于spring-security+jwt与cas-server5.3对接
- 2024-10-01 单点登录(SSO)看这一篇就够了 单点登录的三种实现方式简书
你 发表评论:
欢迎- 最近发表
- 标签列表
-
- oraclesql优化 (66)
- 类的加载机制 (75)
- feignclient (62)
- 一致性hash算法 (71)
- dockfile (66)
- 锁机制 (57)
- javaresponse (60)
- 查看hive版本 (59)
- phpworkerman (57)
- spark算子 (58)
- vue双向绑定的原理 (68)
- springbootget请求 (58)
- docker网络三种模式 (67)
- spring控制反转 (71)
- data:image/jpeg (69)
- base64 (69)
- java分页 (64)
- kibanadocker (60)
- qabstracttablemodel (62)
- java生成pdf文件 (69)
- deletelater (62)
- com.aspose.words (58)
- android.mk (62)
- qopengl (73)
- epoch_millis (61)
本文暂时没有评论,来添加一个吧(●'◡'●)