您的位置 首页 java

.NET、JAVA集成CAS认证超简单方案,无需CAS源码保留应用自身验证

先说下本次.NET网站应用与CAS认证集成的特点

  1. CAS-服务器端默认是已经搭建完毕,且正常运行的,本次方案只针对CAS客户端如何集成介绍。
  2. 无需CAS源码,也无需深层研究CAS服务器端原理,不需要进行繁琐的配置文件修改调整。
  3. 保留应用内部用户信息存储和验证方式不变,如form认证等可以继续保留。
  4. 对应用无需进行任何架构和功能调整,只需要对原登录页面简单新增几行代码即可。
  5. 本次方案介绍一个CAS客户端如何与CAS认证集成,最主要是介绍2个或多个CAS客户端同时与CAS做集成。
  6. 本次集成方案是基于.NET环境通过C#语音中进行的代码示例,同样的逻辑在其他Web应用如 JAVA 、PHP等语言下是一样通用的。
  7. 由于是与多个系统同时做集成,暂时没有考虑如何登出注销的问题,用户浏览器关闭后,存储的用户信息自动消失。

事情起因是最近公司有个项目需要与CAS认证系统做单点集成,CAS服务器端用户已经搭建完成。公司之前做过类似的单点集成,但是没有直接与CAS做认证的,对CAS这块不是很熟悉。所以一开始不打算做了,但是甲方一直要求做,然后给CAS的供应商要了接口文档和说明,本来以为接口会很详细明了,谁知道给的文档都是如何部署JAVA服务器端的文档。不懂JAVA,看文档简直是隔行如隔山,关键文档是如何部署服务器端的,不是介绍第三方应用如何与CAS认证集成的。没办法,最终这个CAS认证我说还是我自己尝试下吧。

然后就开始了 百度 、CSDN的苦逼搜索之路。网上一搜”.NET集成CAS认证”,搜索结果一大片,都有各种介绍和各种原理说明,其中大部分都是需要下载.net版本的 CAS源码进行二次改造集成等等。

一看有源码,好啊!抓紧下载源码,先是下载了最新.NET版本CAS源码,但是在开发环境无法打开,花费了不少时间解决这个问题,最终看到有个文章里面说最新的需要VS2017才能打开,然后又下载了一个适配VS2013版本的源码。

OK,这次可以打开正常调试了,很开心,觉得离成功越来越近了。然后按照介绍进行配置、调试,发布到IIS进行测试。好吧,然后我才发现我掉入到坑里面了。调试到各种问题,如重复定向问题、再次验证失败问题。花了3天时间把整个源码逻辑一步步的跟踪了很多遍,弄懂了大部分代码的功能,但悲哀的是最终要实现的单点效果一直没实现。

然后就继续网上找资源,突然一个简单的代码示例出现在我的眼前

 string CASHOST = "#34;;   //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;
        Stream reader  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接口进行数据获取,完整请求示例为:【】。获取到返回数据后,返回数据格式为XML,解析其中的user节点,即为用户账号。

情形一:【一个CAS-Client与CAS-Server认证集成过程】

下面介绍具体认证过程:

1)终端第一次访问Client1

  • 首先,检测本地没有缓存Client1的用户信息;
  • 然后,检测到请求信息中没有Ticket凭据(即CAS为用户签发的访问某一服务票据);
  • 所以,Client1将请求重定向到CAS—Server(,并传递 Service (也就是要访问的系统A的登录页URL,以便登录成功过后转回该地址)示例【 Service =】

2)终端第一次访问CAS—Server

  • CAS—Server检测到请求信息中没有TGC(即CAS登录成功后在客户端存储的用户信息),所以跳转到自己的登录页;
  • 终端输入用户名、密码,点击登录按钮,认证成功后,CAS—Server会生成一个服务票据—Ticket与CAS会话标识—TGC。大家只需要知道Ticket即可,上面有介绍。
  • 然后,CAS—Server会将Ticket加在url 后面,将请求redirect 回客户web 应用,例如URL为【】

3)终端携带ticket再次请求Client1

注:本次请求是通过CAS登录页面登录成功后,由CAS服务器端重定向跳转到的 Client1 。不属于、也不需要用户主动操作。

  • 这时Client1后台系统看到ticket 参数后,会获取此参数,由其后面的“票据验证”功能进行逻辑处理,不再继续往CAS服务器端进行跳转。
  • Client1“票据验证”功能实现逻辑为:通过http请求,访问cas 服务的/serviceValidate 接口,将ticket 、service 都传到此接口,由此接口验证ticket 的有效性并返回用户数据。请求接口示例为【】
  • 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的登录页,地址示例为【 Service =】。CAS服务器端可以检测到当前客户端环境中存在CAS的用户凭据信息
  • 然后CAS服务器端 不会将当前页面请求转到CAS的登录页,而是会跳过这一步骤,同时生成有效的ticket,携带ticket直接跳转到Client2的登录页 。最终跳转地址如下:【】
  • 后面的过程就和 “情形一:3)终端携带ticket再次请求Client1” 中描述的完全一致了。这样就实现了多个系统直接与CAS认证集成,实现了多个系统的免登陆。

至此,多个CAS-Client与CAS-Server认证集成过程已经顺利完成。

看到这里,大家是不是有豁然开朗的感觉?真是踏破铁鞋无觅处,得来全不费功夫。没想到被CAS源码折磨的死去活来的时候,上面那一段小小的代码竟然能实现全部功能。在这次研究摸索的过程中,也理解了一种新的SSO单点思路。希望能和大家一起功能进步。

文章来源:智云一二三科技

文章标题:.NET、JAVA集成CAS认证超简单方案,无需CAS源码保留应用自身验证

文章地址:https://www.zhihuclub.com/178760.shtml

关于作者: 智云科技

热门文章

网站地图