spring cloud 前后端分离集成CAS client
客户端集成遇到的问题
是否启用CAS (公网登录页一套、内网CAS一套)
jar包原始注解中直接引入,没有提供是否启用的属性
@EnableCasClient
通过自定义注解实现自由开关
@Configuration
@ConditionalOnProperty(name = "casqy.enabled", havingValue = "true")
@Import(CasClientConfiguration.class)
public class ConditionalCasClientConfiguration {
}
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
@Import({ConditionalCasClientConfiguration.class})
public @interface CasClient {
}
cas认证过期固定重定向前端首页
CAS会转发自己系统认证失败的接口地址:
http://127.0.0.1:8080/cas/login?service=http://127.0.0.1:8087/api/auth/cn/dengl
service= 后面跟的就是在CAS认证完后会转发回来的地址,这样就会导致资源接口认证失败就成调用接口,而不是访问回应用系统,所以需要重写CAS redirect 重定向方法
@Configuration
public class CasClientConfig extends CasClientConfigurerAdapter {
@Override
public void configureAuthenticationFilter(FilterRegistrationBean authenticationFilter) {
Map<String, String> initParameters = authenticationFilter.getInitParameters();
initParameters.put("authenticationRedirectStrategyClass", "org.springblade.auth.redirect.CustomAuthRedirectStrategy");
}
@Override
public void configureValidationFilter(FilterRegistrationBean filterRegistrationBean) {
}
@Override
public void configureHttpServletRequestWrapperFilter(FilterRegistrationBean filterRegistrationBean) {
}
@Override
public void configureAssertionThreadLocalFilter(FilterRegistrationBean filterRegistrationBean) {
}
}
@Component
public class CustomAuthRedirectStrategy implements AuthenticationRedirectStrategy {
@Override
public void redirect(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, String s) throws IOException {
StringBuilder stringBuilder = new StringBuilder();
// 1.此处判断请求路径是否是cas/login认证接口请求,但请求报错不是(登录接口:dengl,获取token接口:skipLogin)
// 在cas认证过期时,需要对其他资源调用接口进行限制,所以返回给前端401状态
if(s.contains("/cas/login")&&!s.contains("dengl")&&!s.contains("skipLogin")){
String loginUrl = s.substring(0, s.indexOf("?"));
// 1.1 先找到第一个斜杠(通常位于 "http://" 后)
int firstSlash = loginUrl.indexOf("/") + 2;
// 1.2 再找到下一个斜杠,从刚才找到的斜杠后面开始
int secondSlash = loginUrl.indexOf("/", firstSlash);
// 1.3 如果secondSlash为-1(即之后没有其他斜杠),则截取到字符串末尾
int thirdSlash = secondSlash != -1 ? loginUrl.indexOf("/", secondSlash + 1) : loginUrl.length();
// 1.4 根据找到的斜杠位置截取子字符串
String http = loginUrl.substring(0, secondSlash != -1 ? secondSlash : loginUrl.length());
// 1.5 固定转发访问的接口地址,不固定service里会是转发的前端调用报错接口 (暂时没用)
stringBuilder.append(loginUrl+"?service="+http+"/api/auth/cn/dengl");
// 1.6 固定给401,让前端页面返回首页从获取token开始
httpServletResponse.setStatus(HttpServletResponse.SC_UNAUTHORIZED);
httpServletResponse.setHeader("Location", stringBuilder.toString()); // 提供重定向 URL,但不自动重定向
httpServletResponse.getWriter().write("Unauthorized - Please login at: " + stringBuilder.toString());
}else if(s.contains("/cas/login")&&s.contains("skipLogin")) {
stringBuilder.append(s);
httpServletResponse.sendRedirect(stringBuilder.toString());
}else{
stringBuilder.append(s);
httpServletResponse.sendRedirect(stringBuilder.toString());
}
}
}
博主这边应用系统前端只对登录、登出进行前端url转发。
所以在第一个if中只对应用系统资源访问接口进行判断(排除登录、登出、跳转),请求头返回 401 让前端直接去调用token的获取,这样就解决资源接口访问状态码 302 前端还要自行处理转发问题
CAS跳转前端首页,过期问题
cas过期处理
skipLoginTwo().then(res => {
let data = res.data.data;
if (data===undefined) {
window.location.href=res.request.responseURL;
} else{
//获取token
}
后端处理了转发路径问题,前端直接调用就行
login、logout接口都只返回302状态码,res.data.data都是undefined,当然你也可以在请求头中加标识,前端判断
跨域问题
location /cas/ {
add_header 'Access-Control-Allow-Origin' '*';
add_header 'Access-Control-Allow-Methods' 'GET, POST, OPTIONS';
add_header 'Access-Control-Allow-Headers' 'DNT,X-CustomHeader,Keep-Alive,User-Agent,X-Requested-With,If-Modified-Since,Cache-Control,Content-Type,Authorization';
add_header 'Access-Control-Allow-Credentials' 'true';
proxy_pass http://ip:port;
}
全是通过自己服务器的nginx去转发