环境:
casServer 5.2.6
pac4j-cas 3.0.2
buji-pac4j 4.0.0
shiro 1.9.1 (ruoyi不分离版)
- 集成
先按照这个帖子集成
客户端配置成IP地址
启动两个客户端,在直接写IP地址的情况下就可以实现单点登录和单点登出。 - 域名单点登出
按照上面配置好,把cas服务和客户端地址改成域名,就会发现服务A退出登录,服务B却依然在线,只能等ST过期后才会回到CAS服务登录页面。(不清楚用IP的为什么是可以的,有知道的大佬可以解惑下吗)
2.1 修改配置
重写DefaultCasLogoutHandler
import org.pac4j.core.context.WebContext;
import org.pac4j.core.context.session.SessionStore;
import org.pac4j.cas.logout.DefaultCasLogoutHandler;
public class CusLogoutHandler<C extends WebContext> extends DefaultCasLogoutHandler<C> {
@Override
public void destroySessionBack(final C context, final String ticket) {
final Object trackableSession = getStore().get(ticket);
logger.debug("ticket: {} -> trackableSession: {}", ticket, trackableSession);
if (trackableSession == null) {
logger.error("No trackable session found for back channel logout. Either the session store does not support to track session "
+ "or it has expired from the store and the store settings must be updated (expired data)");
} else {
getStore().remove(ticket);
// renew context with the original session store
final SessionStore sessionStore = context.getSessionStore();
if (sessionStore == null) {
logger.error("No session store available for this web context");
} else {
// newSessionStore就是登录进来保存的session
// 具体可以看org.pac4j.cas.logout.DefaultCasLogoutHandler#recordSession
final SessionStore<C> newSessionStore = sessionStore.buildFromTrackableSession(context,trackableSession);
if (newSessionStore != null) {
logger.debug("newSesionStore: {}", newSessionStore);
// 主要是这里 得获取本次票据ST对应的Shiro的session
final String sessionId = ((CusShiroSessionStore)newSessionStore).getSessionId();
logger.debug("remove sessionId: {}", sessionId);
getStore().remove(sessionId);
destroy(context, newSessionStore, "back");
} else {
logger.error("The session store should be able to build a new session store from the tracked session");
}
}
}
}
}
重写ShiroSessionStore
import io.buji.pac4j.context.ShiroSessionStore;
import org.apache.shiro.session.Session;
import org.pac4j.core.context.J2EContext;
import org.pac4j.core.context.session.SessionStore;
public class CusShiroSessionStore extends ShiroSessionStore {
Session session;
public CusShiroSessionStore(Session session) {
this.session = session;
}
public CusShiroSessionStore() {
}
@Override
public Object getTrackableSession(J2EContext context) {
return getSession(false);
}
@Override
public SessionStore<J2EContext> buildFromTrackableSession(final J2EContext context, final Object trackableSession) {
// 保存ST对应的session
if (trackableSession != null) {
return new CusShiroSessionStore((Session)trackableSession);
} else {
return null;
}
}
@Override
public String getOrCreateSessionId(J2EContext context) {
return super.getOrCreateSessionId(context);
}
public String getSessionId() {
// 当cas退出时会通知客户端,获取缓存中的session并移除
return session.getId().toString();
}
@Override
public boolean destroySession(final J2EContext context) {
if (session != null) {
try {
session.stop();
}catch (Exception e){
}
}
return true;
}
}
修改Pac4jConfig
/**
* 自定义存储
*
* @return
*/
@Bean
public ShiroSessionStore shiroSessionStore() {
return new CusShiroSessionStore();
}
@Bean
public CasConfiguration casConfig() {
final CasConfiguration configuration = new CasConfiguration();
//CAS server登录地址
configuration.setLoginUrl(casServerUrl + "/login");
//CAS 版本,默认为 CAS30,我们使用的是 CAS20
configuration.setProtocol(CasProtocol.CAS20);
configuration.setAcceptAnyProxy(true);
configuration.setPrefixUrl(casServerUrl + "/");
CusLogoutHandler<J2EContext> cusLogoutHandler = new CusLogoutHandler<>();
// 设置是否销毁缓存中的session,其实就是调用缓存的session对象的destroySession方法
// org.pac4j.cas.logout.DefaultCasLogoutHandler#destroy
cusLogoutHandler.setDestroySession(true);
configuration.setLogoutHandler(cusLogoutHandler);
return configuration;
}
到这里就可以实现在域名的情况下单点退出了
2.2 io.buji.pac4j.filter.SecurityFilter验证是否需要重新到cas登录
在org.pac4j.core.engine.DefaultSecurityLogic#perform中
会获取一个profiles,这个profiles就是当前session里存放的本客户端信息(org.pac4j.cas.client.CasClient或继承类)
在执行到后面当profiels为空时才会跳转到cas登录页面
2.3 存在问题
当重写过后客户端,退出来然后在重新登录进来,偶尔会出现请求cas服务端返回401状态,但是只要刷新一下页面重新请求下cas服务端就就没有问题了,相当于是又重新在casRealm里面登录了一次。很奇怪,当然改了之后用IP也会有这种情况。