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:8002cors.origins[0]= http://localhost:9527/
spring.main.allow-bean-definition-overriding=true
3) 重写cas重定向策略
@Configuration
@EnableCasClient
public class CasConfig implements CasClientConfigurer, ConfigurationKeys {@Overridepublic 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 {@Overridepublic 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;}@Beanpublic 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