0. cas服务搭建参考:CAS 5.3服务器搭建_cas-overlay-CSDN博客
1. 参照springsecurity适配cas的方式, 一直失败, 无奈关闭springssecurity认证
2. 后端服务适配cas: 参考前后端分离项目(springboot+vue)接入单点登录cas_前后端分离做cas单点登录-CSDN博客
1) 引入maven依赖
<dependency>
<groupId>org.jasig.cas.client</groupId>
<artifactId>cas-client-support-springboot</artifactId>
<version>3.6.4</version>
</dependency>
2) springboot相关配置
cas.server-url-prefix= http://localhost:8443/cas
cas.server-login-url= http://localhost:8443/cas/login
cas.client-host-url= http://localhost:8002
cors.origins[0]= http://localhost:9527/
spring.main.allow-bean-definition-overriding=true
3) 重写cas重定向策略
@Configuration
@EnableCasClient
public class CasConfig implements CasClientConfigurer, ConfigurationKeys {
@Override
public void configureAuthenticationFilter(FilterRegistrationBean authenticationFilter) {
Map<String, String> initParameters = authenticationFilter.getInitParameters();
initParameters.put(AUTHENTICATION_REDIRECT_STRATEGY_CLASS.getName(), CasRedirectStrategy.class.getName());
}
}
public class CasRedirectStrategy implements AuthenticationRedirectStrategy {
@Override
public void redirect(HttpServletRequest request, HttpServletResponse response, String potentialRedirectUrl) throws IOException {
/* 通过Origin判断前后端分离项目跨域请求 */
if (CommonUtils.isNotBlank(request.getHeader("Origin"))){
/* 跨域处理:cas过滤器优先级高,自定义跨域配置无法处理此请求 */
response.setHeader("Access-Control-Allow-Origin", request.getHeader("Origin"));
response.setHeader("Access-Control-Allow-Credentials","true");
/* 自定义状态码,根据实际情况自定义,前端需对应此值 */
response.setStatus(HttpStatus.NON_AUTHORITATIVE_INFORMATION.value());
}else {
response.sendRedirect(potentialRedirectUrl);
}
}
}
4) 创建login接口处理前端登录请求
@GetMapping("/login")
public void login(HttpServletRequest request, HttpServletResponse response, @RequestParam String url) throws IOException {
ResponseCookie cookie = ResponseCookie.from("JSESSIONID", request.getSession().getId())
.domain(request.getRemoteHost())
.build();
response.setHeader(HttpHeaders.SET_COOKIE, cookie.toString());
response.sendRedirect(url);
}
5) 跨域配置
@Configuration
@ConfigurationProperties(prefix = "cors")
public class CorsConfig {
protected List<String> origins;
public void setOrigins(List<String> origins) {
this.origins = origins;
}
@Bean
public CorsFilter corsFilter() {
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
CorsConfiguration config = new CorsConfiguration();
config.setAllowedOrigins(origins);
config.setAllowCredentials(true);
config.addAllowedHeader("*");
config.addAllowedMethod("*");
source.registerCorsConfiguration("/**", config);
return new CorsFilter(source);
}
}
3. 前端配置
1) 响应拦截器改造
import axios from 'axios'
import { casLogin } from '../utils/cas'
let request = axios.create({
baseURL: import.meta.env.VITE_BACK_URL,
withCredentials: true,
})
request.interceptors.response.use(
if (response.status === 203) {
console.error('ddddddddddddddddddddddd')
const url = encodeURIComponent(window.location.href) /* 登录后跳转到原页面 */
window.location.href = `http://localhost:8002/cims/login?url=${url}`
....
}
)
export default request
2) (只针对自身服务修改, 非通用) 去掉原有的前端token判断代码
todo:后端服务添加认证过滤器, 需要校验用户信息(从cas服务获取)
实现原理分析:
1) 前端访问后台url
2) 后台服务cas拦截器验证未登录,(正常是跳转到cas登录, 前后端分离服务这里跳转会403CORS跨域)将cas重定向修改为返回指定状态码203
3) 前端服务通过http请求拦截器将203状态码 , 然后以浏览器页面跳转的方式跳转到后台新定义的登录url(并携带最终认证后需要跳转的页面) http://localhost:8002/cims/login?url=${url}`
4) 后台服务接收到/login请求后,被cas过滤器重定向cas服务
(为啥第2步里返回状态码203,而这里是cas跳转? 因为后台做了跨域配置 CorsFilter, 前端过来的请求返回状态码, 否则是cas跳转)
(前端做了跨域配置, 前端访问后台的url, 实际上也是前端的ip+port, 所以第一次前端访问后台, 是ajax过来的请求,返回状态码, 如果这时不返状态码而是cas跳转, ajax调到cas服务地址就跨域了, 所以这里返状态码, 然后ajax收到状态码, 以浏览器窗口的方式, 直接访问后台真实的url, 后台真实url就会触发cas重定向了)
5) cas服务页面登录成功后, 跳转回/login请求, /login请求会设置session信息,并重定向到最终的即, 最开始请求的那个url