论如何优雅的将自己的服务接入学校的 CAS 统一认证系统

论如何优雅的将自己的服务接入学校的 CAS 统一认证系统

起因

前几天跟同学聊起一个希望建立校友交流论坛的想法,讨论之中有人表示如果能用学校的统一认证系统登录的话,就可以大大简化注册门槛。于是我开始研究学校的统一认证系统起来……

了解原理

首先我希望找一个使用统一认证系统的学校服务进行测试,在这里,我选择了学校的一站式服务平台,当在尚未登录账号是访问该网站,则会被跳转至统一认证系统进行认证:

Screenshot 2022-09-15 235451

可以看到此时的网页链接为 https://cas.xaufe.edu.cn/login?service=http%3A%2F%2Fmy.xaufe.edu.cn%2Fcjmh%2FcasAuth%3FredirectUrl%3Dmy.xaufe.edu.cn%2Fnewcjmh,配合尝试登录时浏览器产生的网络流:

image-20220916000314362

我们可以得知,该验证系统在登录通过后会 302 跳转到 service 字段所指向的网址,并在 GET 请求中携带一个 ticket,如此一来,我们就大致得知了这套统一认证系统的大致使用流程。但是截至现在,我们仍未知道 ticket 的作用,为此,我查询了大量资料,最终,在 这个网站 得到了我想要的答案:

image-20220916000801788

也就是说,当服务器拿到 ticket 以后,会立刻向 CAS 服务器的 /serviceValidate 路由发起一个 GET 请求,并携带 serviceticket 参数,最后,服务器将会返回用户信息。

当我们知道了这些全部原理后,我们便可以开始将自己的服务对接到这套统一认证系统中。

实践环节

通过开发一个 Spring Boot Web 应用,我尝试对接了 CAS 系统,但是,在实践环节中,我遇到了几个问题:

首先,我发现 CAS 系统的 service 字段允许提交的网址存在访问控制,当我们尝试使用一个不在白名单内的服务地址时,便会产生访问错误:

image-20220916001302081

但是后来我发现,这只是因为我没有在 service 中提供 http:// 头,加上以后,问题便得到了解决(这也要归功于学校为了方便可能允许了所有 HTTP 服务使用认证)

接下来,当我获得 ticket 并试图访问 /serviceValidate 路由时,我得到了一个 403 错误:

image-20220916001528518

这也就意味着,需要通过校园网络才能正常验证。但是,由于学校提供了 WebVPN,因此我们只需要通过 WebVPN 访问该路由即可。

但当我手动从 WebVPN 访问该路由,并携带正确的 ticket 时,我却总是得到一个无法识别 ticket 的错误。后来经过查询,我得知可能是因为 ticket 从发放到验证的过程有一个 timeout,必须在指定时间内进行验证,否则就会导致 ticket 失效。

因此最后,我编写了一个简单的 Controller:该 Controller 负责识别 ticket 并通过 WebVPN 访问 /serviceValidate 进行验证:

image-20220916001943196

在这个过程中,由于 WebVPN 也同样需要登录,方便起见,我直接抓取了 WebVPN 的 cookie,以绕过登录过程(其实由于 WebVPN 服务也使用统一认证系统,因此这里可以进行两次验证 —— 一次登录 WebVPN,一次登录自己的服务)

最后,在 localhost:8080 运行 Spring Boot 服务,并访问 https://cas.xaufe.edu.cn/login?service=http://localhost:8080/check,我成功得到了用户信息:

image-20220916002545022

至此,我们成功将自己的服务接入到了 CAS 认证系统。

最后

其实这套系统还有其不足的地方,但是无论如何,通过这么一阵子下来,我们成功找到了对接服务器 CAS 统一认证系统的方法,这也方便了日常的使用。