前言
本地讲解的是单纯的cas,不掺和springsecurity或者shiro等权限框架
首先说明几点注意事项:
- cas默认不支持前端分离的,这个后便会讲到,也是最大问题所在;
- 前端vue不能直接访问后端接口,否则会报错跨域,即使后端已经配置了跨域,因为cas拦截器的级别太高了;
- 网上有很多解决方法,一般分为两种,一种是引入独立的cas包,也就是
cas-client-core
,第二种就是映入springboot的包,也就是cas-client-support-springboot
,注意区分,本文重点讲的第二种方式
; - 另外就是,cas版本不一样,很多配置项也会发生变化,如果不生效,看看是否版本问题。
总观
先把cas单点登录必要的拦截器说一下,有个映像,切记拦截器的顺序不能乱
SingleSignOutFilter
:退出拦截,负责单点登出功能,放在其他filter之前;IgnoreSSLValidateFilter
:负责忽略SSL认证的;AuthenticationFilter
:这个比较重要,负责用户的认证;Cas20ProxyReceivingTicketValidationFilter
:负责对Ticket,也就是票据进行校验,看版本有的是c30,看cas版本配置;CharacterEncodingFilter
:设置response的默认编码方式:UTF-8;HttpServletRequestWrapperFilter
:很方便的使用request.getRemoteUser()获取用户信息,还有其他过滤器也有类似的功能,比如AssertionThreadLocalFilter,该过滤器使得开发者可以通过org.jasig.cas.client.util.AssertionHolder来获取用户的登录名。
这是最常用的几个拦截器,当然也有监听器,比如SingleSignOutHttpSessionListener,可以监听到session销毁。
问题说明
先说下,流程,做单点登录,我们一般都是客户端,所以,我们要给主系统提供一个地址,用来方便用户点击之后,跳转到我们的系统,那么这个地址就有说法了。
两种方式,前端地址或者后端接口地址。
提供前端地址
1、如果提供的是前端地址,那么当用户从主系统里,通过这个地址跳转到我们的vue前端时,前端要立刻去调后端接口验证这个请求是否合法,没问题就可以正常使用系统了,注意,因为用户是从主系统跳转过来的,此时用户必定是登录状态了,所以,下边的操作肯定是没问题,正常访问的
,但是,如果用户直接请求前端的地址,不从主系统跳转,这个时候会发生什么呢?
说明一下,前端首页打开就会自动请求下边的checkLogin接口
因为我们的后端有cas拦截,如果用户直接访问,势必会被拦截,这个时候cas检测到没有登陆,那么就会重定向到cas的登录页面,但是此时就会出现问题了
后端响应302重定向,前端vue无法重定向,报错跨域,这是因为cas服务端不允许跨域重定向
,即使你的项目里配置了允许跨域,接口里也配置了,拦截器里也配置了,都不行。
那么知道原因了,我们就可以针对解决了,我们要知道一个重要的东西,那就是跨域,跨域问题主要是由于浏览器的同源策略所致
,
既然这样,那么我们不让前端直接跳转,让后端去跳转登录地址,然后登录成功之后再重定向回前端页面即可。
具体的流程就是,前端先访问后端的接口,传递一个约定好的请求头,然后,后端通过拦截器,判断如果是这个请求头,就返回一个状态码和地址(这个地址是后端的地址)给前端,前端判断如果响应的是这个状态码,就直接通过
window.location.href
去访问传递过的后端地址,这样后端拦截之后,直接跳转cas登录页面。
说到这里,细心的朋友一定会发现一个问题:上边的这个方法,最后不都是请求后端接口嘛,为什么第一次报错跨域,无法跳转到cas登录界面,第二次就可以呢?原因就是:
第一次我们请求后端接口是通过ajax,是会出现跨域问题的
;
第二次使用的是 window.location.href ,它是用于设置或获取当前页面的 URL,因此它不存在跨域限制,因为它不涉及到与其他域的数据交换,所以用它是无法获得后端返回数据的,只是在这里解决跨域问题
。
2、还要解决一个问题,前后端的跨域问题(注意:上边说的跨域是发生在前端和cas服务端的),前端请求后端是会跨域的,因为端口不通,因为cas的拦截更靠前,像之前那样,后端配置跨域没作用。
所以这里我们有两种方式来使前后端请求地址一样,这样就算同源了,方法分别是使用代理,一种前端代理,另一种nginx代理。
- 前端代理,我用的是uniapp做的h5,其他的前端项目找到自己的对应位置改
"devServer": {
"https": false,
"proxy": {
"/api": {
"target": "http://192.168.2.189:8010/",
"changeOrigin": true,
// "secure": true,
"pathRewrite": {
"^/api": ""
}
}
}
},
- nginx代理
server {
listen 8092;
server_name 192.168.2.189;
location / {
root html/web/;
index index.html index.htm;
try_files $uri $uri/ /index.html;
}
location /lsdb-api/ {
proxy_pass http://192.168.2.189:8010/lsdb-api/;
proxy_set_header Host $proxy_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root html;
}
}
如果中间报错When allowCredentials is true, allowedOrigins cannot contain the special val
,那就在你自己配置的跨域里改下配置
下边介绍怎么来修改cas自带的拦截器,需要重写cas的拦截器AuthenticationFilter,为了让用户直接访问前端能够正常跳转cas登录页。
第一种配置方式
<dependency>
<groupId>org.jasig.cas.client</groupId>
<artifactId>cas-client-core</artifactId>
<version>3.3.2</version>
</dependency>
具体配置我就不细写了,网上很多,这里提供几个连接,可以直接去找到:
cas单点登录配置 cas配置
大致的方法就是自定义一个拦截器继承AuthenticationFilter
,重写doFilter
,然后不让重定向,改成响应信息给前端,核心代码如下: