shiro buji pac4j cas 单点注销不起作用
Posted
技术标签:
【中文标题】shiro buji pac4j cas 单点注销不起作用【英文标题】:shiro buji pac4j cas single sign out not work 【发布时间】:2020-07-08 02:04:54 【问题描述】:弹簧靴 2.2.5
shiro-spring-boot-web-starter 1.5.1
buji-pac4j 4.1.1
pac4j-cas 3.8.3
cas 覆盖模板 5.3.
我在tomcat中用https启动cas服务器,在eclipse中启动两个客户端(pac4j1
和pac4j2
)。
单点登录有效,但single sign out
失败。
以下是我的配置:
我只在 cas 服务器下添加了 一个 service
文件,如下所示:
"@class": "org.apereo.cas.services.RegexRegisteredService",
"serviceId": "^(http)://localhost.*",
"name": "local",
"id": 10000003,
"evaluationOrder": 1
pac4j1
的application.yml:
server:
port: 8444
servlet:
context-path: /pac4j1
cas:
client-name: pac4j1Client
server:
url: https://localhost:8443/cas
project:
url: http://localhost:8444/pac4j1
Pac4jConfig:
@Configuration
public class Pac4jConfig
@Value("$cas.server.url")
private String casServerUrl;
@Value("$cas.project.url")
private String projectUrl;
@Value("$cas.client-name")
private String clientName;
@Bean("authcConfig")
public Config config(CasClient casClient, ShiroSessionStore shiroSessionStore)
Config config = new Config(casClient);
config.setSessionStore(shiroSessionStore);
return config;
@Bean
public ShiroSessionStore shiroSessionStore()
return new ShiroSessionStore();
@Bean
public CasClient casClient(CasConfiguration casConfig)
CasClient casClient = new CasClient(casConfig);
casClient.setCallbackUrl(projectUrl + "/callback?client_name=" + clientName);
casClient.setName(clientName);
return casClient;
@Bean
public CasConfiguration casConfig()
final CasConfiguration configuration = new CasConfiguration();
configuration.setLoginUrl(casServerUrl + "/login");
configuration.setProtocol(CasProtocol.CAS20);
configuration.setAcceptAnyProxy(true);
configuration.setPrefixUrl(casServerUrl + "/");
return configuration;
shiro 配置:
@Configuration
public class ShiroConfig
@Value("$cas.project.url")
private String projectUrl;
@Value("$cas.server.url")
private String casServerUrl;
@Value("$cas.client-name")
private String clientName;
@Bean("securityManager")
public DefaultWebSecurityManager securityManager(Pac4jSubjectFactory subjectFactory, CasRealm casRealm)
DefaultWebSecurityManager manager = new DefaultWebSecurityManager();
manager.setRealm(casRealm);
manager.setSubjectFactory(subjectFactory);
return manager;
@Bean
public CasRealm casRealm()
CasRealm realm = new CasRealm();
realm.setClientName(clientName);
realm.setCachingEnabled(false);
realm.setAuthenticationCachingEnabled(false);
realm.setAuthorizationCachingEnabled(false);
return realm;
@Bean
public Pac4jSubjectFactory subjectFactory()
return new Pac4jSubjectFactory();
@Bean
public FilterRegistrationBean<SingleSignOutFilter> singleSignOutFilter()
FilterRegistrationBean<SingleSignOutFilter> bean = new FilterRegistrationBean<SingleSignOutFilter>();
bean.setName("singleSignOutFilter");
SingleSignOutFilter singleSignOutFilter = new SingleSignOutFilter();
singleSignOutFilter.setCasServerUrlPrefix(casServerUrl);
singleSignOutFilter.setIgnoreInitConfiguration(true);
bean.setFilter(singleSignOutFilter);
bean.addUrlPatterns("/*");
bean.setEnabled(true);
bean.setOrder(Ordered.HIGHEST_PRECEDENCE);
return bean;
@Bean
public FilterRegistrationBean<DelegatingFilterProxy> filterRegistrationBean()
FilterRegistrationBean<DelegatingFilterProxy> filterRegistration = new FilterRegistrationBean<DelegatingFilterProxy>();
filterRegistration.setFilter(new DelegatingFilterProxy("shiroFilter"));
filterRegistration.addInitParameter("targetFilterLifecycle", "true");
filterRegistration.setEnabled(true);
filterRegistration.addUrlPatterns("/*");
filterRegistration.setDispatcherTypes(DispatcherType.REQUEST, DispatcherType.FORWARD);
return filterRegistration;
private void loadShiroFilterChain(ShiroFilterFactoryBean shiroFilterFactoryBean)
Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>();
filterChainDefinitionMap.put("/", "securityFilter");
filterChainDefinitionMap.put("/index", "securityFilter");
filterChainDefinitionMap.put("/callback", "callbackFilter");
filterChainDefinitionMap.put("/logout", "logout");
filterChainDefinitionMap.put("/**","anon");
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
@Bean("shiroFilter")
public ShiroFilterFactoryBean factory(DefaultWebSecurityManager securityManager, Config config)
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
shiroFilterFactoryBean.setSecurityManager(securityManager);
loadShiroFilterChain(shiroFilterFactoryBean);
Map<String, Filter> filters = new HashMap<>(3);
SecurityFilter securityFilter = new SecurityFilter();
securityFilter.setConfig(config);
securityFilter.setClients(clientName);
filters.put("securityFilter", securityFilter);
MyCallbackFilter callbackFilter = new MyCallbackFilter();
callbackFilter.setConfig(config);
callbackFilter.setDefaultUrl(projectUrl);
filters.put("callbackFilter", callbackFilter);
LogoutFilter logoutFilter = new LogoutFilter();
logoutFilter.setConfig(config);
logoutFilter.setCentralLogout(true);
logoutFilter.setLocalLogout(true);
logoutFilter.setDefaultUrl(projectUrl + "/callback?client_name=" + clientName);
filters.put("logout",logoutFilter);
shiroFilterFactoryBean.setFilters(filters);
return shiroFilterFactoryBean;
cas server
的application.properties
是默认值,cas server
使用 https(https://localhost:8443/cas
) 而 cas clients
是 http(http://localhost:8444/pac4j1
)。
我哪里错了?
【问题讨论】:
客户端应用程序有自己的会话吗? @leopal 你的意思是我需要在客户端应用程序中明确设置会话吗?我应该在哪里以及如何设置?我定义了扩展Pac4jRealm
的CasRealm
,扩展了CallbackFilter
的MyCallbackFilter
,扩展了CasClient
的MyCasClient
,Pac4jConfig
和ShiroConfig
。
好吧,我不熟悉你的堆栈,但我可以提供一些有用的网址。结帐SLO 和SingleSignOutFilter 的java-cas-client
。您可能必须为您的案例实施类似的操作。我希望我能帮助你更多。
@leopal 非常感谢您,您提供的链接非常有用,我从中得到了提示。
【参考方案1】:
借助leopal
提供的链接SLO,我知道cas服务器需要将注销请求发送回客户端。
于是,我查看了 cas server 的日志,发现INFO [org.apereo.cas.logout.DefaultLogoutManager] - <Performing logout operations for
。
所以我为org.apereo.cas.logout
添加了日志,发现有一些关于注销的类:DefaultLogoutManager
、DefaultSingleLogoutServiceLogoutUrlBuilder
、DefaultSingleLogoutServiceMessageHandler
和SimpleUrlValidator
。
在执行注销时,DefaultSingleLogoutServiceLogoutUrlBuilder.determineLogoutUrl
将从注册服务获取注销 url,如果原始 url 是有效 url,则从 cas 客户端获取原始 url。
所以我的问题是:我没有在服务 json 文件中定义注销 url,而来自 cas 客户端的原始 url 是 localhost:8444
,这是一个无效的 ipv4。因此,cas server 不会向客户端发送注销请求。
解决方案是:在项目url中使用ip
,而不是cas客户端的application.yml
中的localhost
:
cas:
client-name: pac4j1Client
server:
url: https://localhost:8443/cas
project:
url: http://192.168.2.119:8444/pac4j1
为每个 cas 客户端服务 json 文件设置另一个解决方案 logoutUrl
(尚未尝试)。
【讨论】:
以上是关于shiro buji pac4j cas 单点注销不起作用的主要内容,如果未能解决你的问题,请参考以下文章