日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) >

CAS单点登出,调整CAS源码,实现前后端分离单点登出、清除redis、shiro登录状态

發(fā)布時(shí)間:2024/1/1 44 豆豆
生活随笔 收集整理的這篇文章主要介紹了 CAS单点登出,调整CAS源码,实现前后端分离单点登出、清除redis、shiro登录状态 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

前端點(diǎn)擊“登出”按鈕,跳轉(zhuǎn)到CAS的登出。

CAS默認(rèn)配置了單點(diǎn)登出,在登出后,會(huì)向所有客戶端系統(tǒng)發(fā)送這個(gè)用戶登出的報(bào)文。

各客戶端系統(tǒng)有責(zé)任接收并處理這個(gè)用戶登出的報(bào)文,然后在注銷該用戶會(huì)話在本客戶端的信息。

若不進(jìn)行 #CAS配置客戶端地址#客戶端后端 ,則網(wǎng)頁(yè)里的登出按鈕點(diǎn)擊之后就無(wú)法通知其他客戶端系統(tǒng)登出。

目前使用了客戶端集成CAS源碼并修改的方法,來(lái)對(duì)客戶端做了Filter接收CAS登出請(qǐng)求之后的處理。
有悖于CAS的建議"不要修改CAS源碼"。待以后再研究看有沒(méi)有什么優(yōu)化方法。

CAS配置客戶端地址

??CAS的單點(diǎn)登出是默認(rèn)啟用的。
??CAS向客戶端發(fā)送地址,默認(rèn)為客戶端請(qǐng)求的URL。但該請(qǐng)求的URL是客戶端的前端地址(含端口),CAS需要向客戶端的后端發(fā)送請(qǐng)求。因此需要對(duì)對(duì)CAS配置客戶端的指定地址。

??CAS 對(duì)客戶端信息的存儲(chǔ)在/services/目錄下,這里配置jl-iam-client的信息,文件命名為iam-client-10000003.json,內(nèi)容如下。
??其中

  • @class - 按默認(rèn)填寫
  • serviceId - 正則表達(dá)式匹配客戶端請(qǐng)求到CAS的來(lái)源URL,這里是前端的地址。因?yàn)檎?qǐng)求都是從前端window.location.href過(guò)來(lái)的。
  • name - 客戶端名稱
  • id - ID,不要重復(fù)
  • description - 描述
  • evalutionOrder - 順序。一個(gè)客戶端的URL匹配成功了多個(gè)客戶端信息,以evalutionOrder最小的來(lái)處理。
  • logoutType - 登出類型。可填"BACK_CHANNEL"或"FRONT_CHANNEL",分別對(duì)應(yīng)后端方式、前端方式。以不配置此項(xiàng),則默認(rèn)是"BACK_CHANNEL"。這里使用后端方式登出。
  • logoutUrl - 登出URL。如果不配置此項(xiàng),CAS會(huì)向來(lái)源URL發(fā)送登出請(qǐng)求。在前后端分離的結(jié)構(gòu)下,來(lái)源是前端地址,與后端地址不同。因此需要配置該項(xiàng)為后端地址

該地址最后為上下文根+“/”。然后不需再有其他字符。
上下文根一定要有!
上下文根后的"/"一定要有!
否則無(wú)法訪問(wèn)到客戶端的Filter。另外,由于配置單點(diǎn)登出的Filter過(guò)濾URL樣式為"/*",因此后面不需要加其他字符。

{"@class" : "org.apereo.cas.services.RegexRegisteredService","serviceId" : "^(http)://192.168.2.111:8086.*","name" : "iam-client","id" : 10000003,"description" : "iam-client info","evaluationOrder" : 1,"logoutType" : "BACK_CHANNEL","logoutUrl" : "http://192.168.2.111:8082/iam-client/" }

客戶端后端

配置Filter

??客戶端(jl-iam-client)需要配置Filter來(lái)接收CAS單點(diǎn)登出的請(qǐng)求。
??接收請(qǐng)求后需要做這些處理:記錄登出日志、刪除Redis信息、調(diào)用Shiro的logout。

??在cas-client-core中的SingleSignOutFilter清空了Session,但是并沒(méi)有其他處理。
??由于目前還沒(méi)有找到追增處理的方法,因此現(xiàn)在將cas-client-core的SingleSignOutFilter以及SingleSignOutHandler重寫在工程里,對(duì)登出處理做了一些定制。

??客戶端使用springboot構(gòu)建。使用@WebFilter 注解,將定制的SingleSignOutFilter注冊(cè)為Filter。

注意注解的參數(shù)配置。

@WebFilter(urlPatterns = "/*", initParams = {@WebInitParam(name = "casServerUrlPrefix", value = "https://cas.example.com:8443/cas") }) public class SingleSignOutFilter extends AbstractConfigurationFilter {

設(shè)置回調(diào)方法

??注銷時(shí)刪除Session的方法,是在SingleSignOutHandler的destroySession()方法中執(zhí)行的,并且CAS的票據(jù)ticket也是在該方法中解析到的。
??在SingleSignOutHandler中,設(shè)置一個(gè)回調(diào)方法,在destroySession()方法中調(diào)用。

回調(diào)方法定義

額外登出策略類 ExtraLogoutStrategy.java

public interface ExtraLogoutStrategy {/*** 登出方法* @param ticket CAS票據(jù)*/void logout(String ticket); }

額外登出策略實(shí)現(xiàn)類 CasLogoutStrategy.java

public class CasLogoutStrategy implements ExtraLogoutStrategy {@Autowiredprivate RedisUtil redisUtil;@Autowiredprivate ISysBaseAPI sysBaseAPI;@Resourceprivate BaseCommonService baseCommonService;@Overridepublic void logout(String ticket) {String token = redisUtil.get(CommonConstant.PRIFIX_CAS_TICKET + ticket).toString();String username = JwtUtil.getUsername(token);LoginUser sysUser = sysBaseAPI.getUserByName(username);if(sysUser != null) {baseCommonService.addLog("用戶名: "+sysUser.getRealname()+",退出成功!", CommonConstant.LOG_TYPE_1, null,sysUser);log.info(" 用戶名: "+sysUser.getRealname()+",退出成功!");//清空用戶登錄CAS ticket緩存redisUtil.del(CommonConstant.PRIFIX_CAS_TICKET + ticket);//清空用戶登錄Token緩存redisUtil.del(CommonConstant.PREFIX_USER_TOKEN + token);//清空用戶登錄Shiro權(quán)限緩存redisUtil.del(CommonConstant.PREFIX_USER_SHIRO_CACHE + sysUser.getId());//清空用戶的緩存信息(包括部門信息),例如sys:cache:user::<username>redisUtil.del(String.format("%s::%s", CacheConstant.SYS_USERS_CACHE, sysUser.getUsername()));//調(diào)用shiro的logoutSecurityUtils.getSubject().logout();}} }

調(diào)整CAS源碼 SingleSignOutHandler.java

/** 額外登出處理策略回調(diào)類 **/private ExtraLogoutStrategy extraLogoutStrategy; /*** 設(shè)置額外登出策略* @param extraLogoutStrategy 額外登出策略*/public void setExtraLogoutStrategy(ExtraLogoutStrategy extraLogoutStrategy) {this.extraLogoutStrategy = extraLogoutStrategy;}

回調(diào)方法設(shè)置

修改部分 調(diào)整CAS源碼 SingleSignOutFilter.java

@WebFilter(urlPatterns = "/*", initParams = {@WebInitParam(name = "casServerUrlPrefix", value = "https://iamlocal.90tech.cn:8443/cas") }) @Qualifier("casLogoutStrategy")@Autowiredprivate ExtraLogoutStrategy casLogoutStrategy; HANDLER.setExtraLogoutStrategy(casLogoutStrategy);

完整類 SingleSignOutFilter.java

@Slf4j @WebFilter(urlPatterns = "/*", initParams = {@WebInitParam(name = "casServerUrlPrefix", value = "https://iamlocal.90tech.cn:8443/cas") }) public class SingleSignOutFilter extends AbstractConfigurationFilter {private static final SingleSignOutHandler HANDLER = new SingleSignOutHandler();private final AtomicBoolean handlerInitialized = new AtomicBoolean(false);@Qualifier("casLogoutStrategy")@Autowiredprivate ExtraLogoutStrategy casLogoutStrategy;@Overridepublic void init(final FilterConfig filterConfig) throws ServletException {log.info("SingleSignOutFilter init.");super.init(filterConfig);if (!isIgnoreInitConfiguration()) {setArtifactParameterName(getString(ConfigurationKeys.ARTIFACT_PARAMETER_NAME));setLogoutParameterName(getString(ConfigurationKeys.LOGOUT_PARAMETER_NAME));setRelayStateParameterName(getString(ConfigurationKeys.RELAY_STATE_PARAMETER_NAME));setLogoutCallbackPath(getString(ConfigurationKeys.LOGOUT_CALLBACK_PATH));HANDLER.setArtifactParameterOverPost(getBoolean(ConfigurationKeys.ARTIFACT_PARAMETER_OVER_POST));HANDLER.setEagerlyCreateSessions(getBoolean(ConfigurationKeys.EAGERLY_CREATE_SESSIONS));HANDLER.setExtraLogoutStrategy(casLogoutStrategy);}HANDLER.init();handlerInitialized.set(true);}

回調(diào)方法調(diào)用

修改部分 調(diào)整CAS源碼 SingleSignOutHandler.destroySession()

if (this.extraLogoutStrategy != null) {this.extraLogoutStrategy.logout(token);}

完整方法 SingleSignOutHandler.destroySession()

/*** Destroys the current HTTP session for the given CAS logout request.** @param request HTTP request containing a CAS logout message.*/private void destroySession(final HttpServletRequest request) {String logoutMessage = CommonUtils.safeGetParameter(request, this.logoutParameterName, this.safeParameters);if (CommonUtils.isBlank(logoutMessage)) {logger.error("Could not locate logout message of the request from {}", this.logoutParameterName);return;}if (!logoutMessage.contains("SessionIndex")) {logoutMessage = uncompressLogoutMessage(logoutMessage);}logger.trace("Logout request:\n{}", logoutMessage);final String token = XmlUtils.getTextForElement(logoutMessage, "SessionIndex");if (CommonUtils.isNotBlank(token)) {final HttpSession session = this.sessionMappingStorage.removeSessionByMappingId(token);if (session != null) {final String sessionID = session.getId();logger.debug("Invalidating session [{}] for token [{}]", sessionID, token);try {session.invalidate();} catch (final IllegalStateException e) {logger.debug("Error invalidating session.", e);}this.logoutStrategy.logout(request);if (this.extraLogoutStrategy != null) {this.extraLogoutStrategy.logout(token);}}}}

CAS ticket緩存

??在CAS代碼處理中,是以接收到的ticket為憑據(jù)的。我的系統(tǒng)通過(guò)緩存token實(shí)現(xiàn)認(rèn)證。
??所以,為了CAS能與系統(tǒng)成功交互,需要將CAS ticket緩存,并與系統(tǒng)中的token建立關(guān)聯(lián)。

上文 #額外登出策略實(shí)現(xiàn)類 CasLogoutStrategy.java 中,已經(jīng)通過(guò)CAS ticket緩存取到了token,并將ticket和token的緩存數(shù)據(jù)都刪除了。

修改部分

// 設(shè)置超時(shí)時(shí)間redisUtil.set(CommonConstant.PREFIX_USER_TOKEN + token, token);redisUtil.expire(CommonConstant.PREFIX_USER_TOKEN + token, JwtUtil.EXPIRE_TIME*2 / 1000);redisUtil.set(CommonConstant.PRIFIX_CAS_TICKET + ticket, token);redisUtil.expire(CommonConstant.PRIFIX_CAS_TICKET + ticket, JwtUtil.EXPIRE_TIME*2 / 1000);

總結(jié)

以上是生活随笔為你收集整理的CAS单点登出,调整CAS源码,实现前后端分离单点登出、清除redis、shiro登录状态的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。