CAS
https://apereo.github.io/cas/5.1.x/protocol/CAS-Protocol.html
CAS 是 Central Authentication Service 的缩写,中央认证服务,一种独立开放指令协议。CAS 是 耶鲁大学发起的一个开源项目,旨在为 Web 应用系统提供一种可靠的单点登录方法,CAS 在 2004 年 12 月正式成为 JA-SIG 的一个项目。
CAS 协议是一种简单且功能强大的基于 ticket 票证的协议。
CAS server 和 CAS client
-
CAS server CAS 服务器,需要独立部署的 Web 应用,主要负责验证用户和授予应用程序的访问权限。 CAS服务器是基于Spring框架构建的Java Servlet,其主要职责是通过发行和验证票证来认证用户并授予对启用CAS的服务(通常称为CAS客户端)的访问权限。当服务器在成功登录后向用户颁发授予票据的票证(TGT)时,将创建SSO会话。应用户的请求,使用TGT作为令牌,通过浏览器重定向将服务票证(ST)发行给服务。随后通过反向通道通信在CAS服务器上验证ST。
-
CAS client
CAS (versions 1, 2, and 3)
SAML 1.1 and 2
OpenID Connect
OpenID
OAuth 2.0
WS Federation
TGT & ST
-
TGT (Ticket Granting Ticket) 授予票据的票证,代表一个用户的 SSO 会话(SSO Session),保存在 TGC cookie 中
-
ST(Service Ticket) ST 使用 url 中的 GET 参数进行传输,代表 CAS 服务器为特定用户授予对 CASified 应用程序的访问。
默认情况下,cas-client-core.jar 会验证请求的会话是否有登录过,如果没有登录,就会驱动浏览器做 302 跳转到 cas 的登录页面。
前后端代码在一起时:
1. 在浏览器请求 GET http://localhost:8080/demo/index.html,请求直接到达后端服务器
2. cas-client-core.jar 验证请求的会话没有登录过,驱动浏览器做 302 跳转到 cas 登录地址
前后端代码分离时:
1. 在浏览器请求 `GET http://localhost/front/index.html`,请求先到达 Nginx,返回静态页面 index.html 给浏览器
2. index.html 中 ajax 请求后端 http://localhost:8080/demo/loginInfo,请求先到达 Nginx,再由 Nginx 转发到端服务器
3. cas-client-core.jar 验证请求的会话没有登录过,驱动浏览器做 302 跳转到 cas 登录地址,出现跨域错误,跳转失败。
(原因:由于 cas 服务器的域和 `http://localhost/front/index.html` 的域不是同一个域,受浏览器同源策略的限制,就会出现跨域错误)
```text
Access to XMLHttpRequest at 'http://cas.sit.xx.com/cas/login?service=http%3A%2F%2Flocalhost%2Fdemo%2FloginInfo' (redirected from 'http://localhost/demo/loginInfo') from origin 'http://localhost' has been blocked by CORS policy: Response to preflight request doesn't pass access control check: No 'Access-Control-Allow-Origin' header is present on the requested resource.
```
所以,前后端分离的情况下,不能使用 cas-client-core.jar 默认的鉴权策略,sf-boot 重写了鉴权策略(DefaultAjaxAuthenticationRedirectStrategy),当鉴权不通过时,返回一串 json 给浏览器,json 中包含了 cas 的跳转地址,开发者通过这个地址来完成 cas 的跳转,从而避开跨域错误。
前后端代码分离时,添加鉴权配置 DefaultAjaxAuthenticationRedirectStrategy:
1. 在浏览器请求 `GET http://localhost/front/index.html`,请求先到达 Nginx,返回静态页面 index.html 给浏览器
2. index.html 中 ajax 请求后端 http://localhost:8080/demo/loginInfo,请求先到达 Nginx,再由 Nginx 转发到端服务器
3. cas-client-core.jar 验证请求的会话没有登录过,DefaultAjaxAuthenticationRedirectStrategy 返回鉴权失败的 json 给浏览器。(json 中包含了 cas 的跳转地址)
4. 前端拿到 json 返回后,取出 cas 跳转地址跳转到 cas 登录页面。
cas 登录页面登录成功后生成的 ticket 是跟回调地址的域绑定在一起的。
前后端分离时,cas 的回调地址肯定是前端 Nginx 的域(这样才能展示页面,如果回调的是后端,那么返回的是 json,就不能展示页面了),所以,cas 的 ticket 是跟 Nginx 的域绑定在一起的。
所以,后端服务的 cas client 的配置应当配置成前端 Nginx 的域。
CAS 浏览器单点登录流程:
CAS Proxy流程: