若依框架是目前比较流行的开源框架,包含普通版、前端分离版、微服务版、移动端版等多个产品线,满足用户不同业务场景应用。
在工作过程中,不免会遇到接入CAS单点登录的业务需求,若依官网提供了普通版集成cas实现单点登录认证的文档,但是前端分离版、微服务版并未提供相关文档,本文将解决若依前端分离版集成cas实现单点登录认证,并解决登录成功后默认只能重定向到首页的问题。
一、集成CAS实现单点登录
参考https://gitee.com/ggxforever/RuoYi-Vue-cas,实现单点登录。
修改CasAuthenticationSuccessHandler.java文件,增加casCookie.setPath(“/”); 否则会出现前端获取不到cookie的情况。
二、解决登录成功只跳转首页
(一)前端
1、修改settings.js文件
/*** 开启cas*/
casEnable: true,
/** * 单点登录url 前面是后端地址,后面是前端地址*/
casloginUrl: 'http://127.0.0.1:8787/?redirect=http://127.0.0.1:88',
/** * 单点登出url */
caslogoutUrl: 'http://127.0.0.1:8888/cas/logout?service=http://127.0.0.1:88'
2、修改permission.js文件
// 没有tokenif (whiteList.indexOf(to.path) !== -1) {
if (to.path === '/login' && defaultSettings.casEnable) {
// 否则全部重定向到访问页
window.location.href = defaultSettings.casloginUrl+to.fullPath
} else {
// 在免登录白名单,直接进入
next()
}
} else {
//cas
if (!defaultSettings.casEnable) {
next(`/login?redirect=${to.fullPath}`) // 否则全部重定向到登录页
}
if (defaultSettings.casEnable) {
// 否则全部重定向到访问页
window.location.href = defaultSettings.casloginUrl+to.fullPath
}
NProgress.done()
}
(二)后端
1、重写
CasAuthenticationEntryPoint
import com.ruoyi.common.utils.StringUtils;
import org.springframework.security.cas.web.CasAuthenticationEntryPoint;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* @author LuoFei
* @className: CustomCasAuthenticationEntryPoint
* @projectName RuoYi-Vue-master
* @description: TODO
* @date 2022/5/25 17:27
*/publicclassCustomCasAuthenticationEntryPointextendsCasAuthenticationEntryPoint{
private String serviceUrlBak=null;
@Overrideprotected String createServiceUrl(HttpServletRequest request, HttpServletResponse response){
if (serviceUrlBak==null) {
serviceUrlBak = getServiceProperties().getService();
}
//将前端登录成功后跳转页面加入CAS请求中if(serviceUrlBak!=null){
String queryString=request.getQueryString();
if (StringUtils.isNotNull(queryString)) {
String serviceUrl = "";
if (queryString.contains("redirect")) {
if (StringUtils.isNotBlank(queryString)) {
serviceUrl = "?" + queryString;
}
}
getServiceProperties().setService(serviceUrlBak + serviceUrl);
}
}
returnsuper.createServiceUrl(request, response);
}
}
2、修改SecurityConfig 认证入口
/**
* 认证的入口
*/
@Bean
public CasAuthenticationEntryPoint casAuthenticationEntryPoint(){
CasAuthenticationEntryPoint casAuthenticationEntryPoint = new CustomCasAuthenticationEntryPoint();
casAuthenticationEntryPoint.setLoginUrl(casProperties.getCasServerLoginUrl());
casAuthenticationEntryPoint.setServiceProperties(serviceProperties());
return casAuthenticationEntryPoint;
}
3、修改
CasAuthenticationSuccessHandler
import com.ruoyi.common.constant.Constants;
import com.ruoyi.common.core.domain.model.LoginUser;
import com.ruoyi.framework.config.properties.CasProperties;
import com.ruoyi.framework.web.service.TokenService;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.tomcat.util.http.SameSiteCookies;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.HttpHeaders;
import org.springframework.http.ResponseCookie;
import org.springframework.security.core.Authentication;
import org.springframework.security.web.authentication.SavedRequestAwareAuthenticationSuccessHandler;
import org.springframework.security.web.savedrequest.HttpSessionRequestCache;
import org.springframework.security.web.savedrequest.RequestCache;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import javax.servlet.ServletException;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import java.io.IOException;
/**
* @author LuoFei
* @className: CasAuthenticationSuccessHandler
* @projectName RuoYi-Vue-master
* @description: TODO
* @date 2022/7/7 10:00
*/
@ServicepublicclassCasAuthenticationSuccessHandlerextendsSavedRequestAwareAuthenticationSuccessHandler{
protected finalLog logger = LogFactory.getLog(this.getClass());
privateRequestCache requestCache = new HttpSessionRequestCache();
@AutowiredprivateTokenService tokenService;
@AutowiredprivateCasProperties casProperties;
/**
* 令牌有效期(默认30分钟)
*/
@Value("${token.expireTime}")
private int expireTime;
@Overridepublic void onAuthenticationSuccess(HttpServletRequest request, HttpServletResponse response,
Authentication authentication) throwsServletException, IOException {
String targetUrlParameter = getTargetUrlParameter();
if (isAlwaysUseDefaultTargetUrl()
|| (targetUrlParameter != null && StringUtils.hasText(request.getParameter(targetUrlParameter)))) {
requestCache.removeRequest(request, response);
super.onAuthenticationSuccess(request, response, authentication);
return;
}
clearAuthenticationAttributes(request);
LoginUser userDetails = (LoginUser) authentication.getPrincipal();
String token = tokenService.createToken(userDetails);
//往Cookie中设置tokenCookie casCookie = new Cookie(Constants.WEB_TOKEN_KEY, token);
casCookie.setMaxAge(expireTime * 60);
casCookie.setPath("/");
response.addCookie(casCookie);
//设置后端认证成功标识HttpSession httpSession = request.getSession();
httpSession.setAttribute(Constants.CAS_TOKEN, token);
//登录成功后跳转到前端访问页面String url = request.getParameter("redirect");
getRedirectStrategy().sendRedirect(request, response, url);
}
}
至此,用户登录成功后跳转页面为用户访问页面。
单点登出及跨域问题将在后面文章介绍。