900字范文,内容丰富有趣,生活中的好帮手!
900字范文 > CAS单点登出 调整CAS源码 实现前后端分离单点登出 清除redis shiro登录状态

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

时间:2020-09-02 15:03:28

相关推荐

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

前端点击“登出”按钮,跳转到CAS的登出。

CAS默认配置了单点登出,在登出后,会向所有客户端系统发送这个用户登出的报文。

各客户端系统有责任接收并处理这个用户登出的报文,然后在注销该用户会话在本客户端的信息。

若不进行#CAS配置客户端地址#客户端后端,则网页里的登出按钮点击之后就无法通知其他客户端系统登出。

目前使用了客户端集成CAS源码并修改的方法,来对客户端做了Filter接收CAS登出请求之后的处理。

有悖于CAS的建议"不要修改CAS源码"。待以后再研究看有没有什么优化方法。

CAS配置客户端地址

CAS的单点登出是默认启用的。

CAS向客户端发送地址,默认为客户端请求的URL。但该请求的URL是客户端的前端地址(含端口),CAS需要向客户端的后端发送请求。因此需要对对CAS配置客户端的指定地址。

CAS 对客户端信息的存储在/services/目录下,这里配置jl-iam-client的信息,文件命名为iam-client-10000003.json,内容如下。

其中

@class - 按默认填写serviceId - 正则表达式匹配客户端请求到CAS的来源URL,这里是前端的地址。因为请求都是从前端window.location.href过来的。name - 客户端名称id - ID,不要重复description - 描述evalutionOrder - 顺序。一个客户端的URL匹配成功了多个客户端信息,以evalutionOrder最小的来处理。logoutType - 登出类型。可填"BACK_CHANNEL"或"FRONT_CHANNEL",分别对应后端方式、前端方式。以不配置此项,则默认是"BACK_CHANNEL"。这里使用后端方式登出。logoutUrl - 登出URL。如果不配置此项,CAS会向来源URL发送登出请求。在前后端分离的结构下,来源是前端地址,与后端地址不同。因此需要配置该项为后端地址

该地址最后为上下文根+“/”。然后不需再有其他字符。

上下文根一定要有!

上下文根后的"/"一定要有!

否则无法访问到客户端的Filter。另外,由于配置单点登出的Filter过滤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来接收CAS单点登出的请求。

接收请求后需要做这些处理:记录登出日志、删除Redis信息、调用Shiro的logout。

cas-client-core中的SingleSignOutFilter清空了Session,但是并没有其他处理。

由于目前还没有找到追增处理的方法,因此现在将cas-client-coreSingleSignOutFilter以及SingleSignOutHandler重写在工程里,对登出处理做了一些定制。

客户端使用springboot构建。使用@WebFilter 注解,将定制的SingleSignOutFilter注册为Filter。

注意注解的参数配置。

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

设置回调方法

注销时删除Session的方法,是在SingleSignOutHandlerdestroySession()方法中执行的,并且CAS的票据ticket也是在该方法中解析到的。

SingleSignOutHandler中,设置一个回调方法,在destroySession()方法中调用。

回调方法定义

额外登出策略类 ExtraLogoutStrategy.java

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

额外登出策略实现类 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权限缓存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()));//调用shiro的logoutSecurityUtils.getSubject().logout();}}}

调整CAS源码 SingleSignOutHandler.java

/** 额外登出处理策略回调类 **/private ExtraLogoutStrategy extraLogoutStrategy;

/*** 设置额外登出策略* @param extraLogoutStrategy 额外登出策略*/public void setExtraLogoutStrategy(ExtraLogoutStrategy extraLogoutStrategy) {this.extraLogoutStrategy = extraLogoutStrategy;}

回调方法设置

修改部分 调整CAS源码 SingleSignOutFilter.java

@WebFilter(urlPatterns = "/*", initParams = {@WebInitParam(name = "casServerUrlPrefix", value = ":8443/cas")})

@Qualifier("casLogoutStrategy")@Autowiredprivate ExtraLogoutStrategy casLogoutStrategy;

HANDLER.setExtraLogoutStrategy(casLogoutStrategy);

完整类 SingleSignOutFilter.java

@Slf4j@WebFilter(urlPatterns = "/*", initParams = {@WebInitParam(name = "casServerUrlPrefix", value = ":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);}

回调方法调用

修改部分 调整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为凭据的。我的系统通过缓存token实现认证。

所以,为了CAS能与系统成功交互,需要将CAS ticket缓存,并与系统中的token建立关联。

上文 #额外登出策略实现类 CasLogoutStrategy.java 中,已经通过CAS ticket缓存取到了token,并将ticket和token的缓存数据都删除了。

修改部分

// 设置超时时间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);

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。