CAS 4.X.X 客户端循环重定向如何查找原因以及解决方案?
问题描述
CAS Server(支持https)下存在client1
,client2
,client3
多个应用,其中client1
和client2
可以正常支持单点登录,但是client3
却不行, 出现的问题是当在CAS Server登录后,网页会在https://cas-server/login?service=https://localhost:8443/cas-client3/login
与https://localhost:8443/cas-client3/login?ticket=ST-1645-XXXXXXX-cas01.example.org
之间循环重定向,导致网页不能正常访问
问题截图
spring security和CAS的配置如下
配置文件
# CAS 相关配置
app:
login:
url: /login
logout:
url: /logout
server:
host:
url: https://localhost:8443/cas-client3
cas:
server:
host:
url: https://cas-server
login_url: ${cas.server.host.url}/login
logout_url: ${cas.server.host.url}/logout?service=${app.server.host.url}
配置类
import com.cloume.mooc.security.MyPermissionEvaluator;
import com.cloume.mooc.security.SpringContextUtil;
import org.jasig.cas.client.session.SingleSignOutFilter;
import org.jasig.cas.client.validation.Cas20ServiceTicketValidator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import org.springframework.security.cas.ServiceProperties;
import org.springframework.security.cas.authentication.CasAssertionAuthenticationToken;
import org.springframework.security.cas.authentication.CasAuthenticationProvider;
import org.springframework.security.cas.web.CasAuthenticationEntryPoint;
import org.springframework.security.cas.web.CasAuthenticationFilter;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.session.SessionRegistry;
import org.springframework.security.core.session.SessionRegistryImpl;
import org.springframework.security.core.userdetails.AuthenticationUserDetailsService;
import org.springframework.security.web.access.expression.DefaultWebSecurityExpressionHandler;
import org.springframework.security.web.authentication.logout.LogoutFilter;
import org.springframework.security.web.authentication.logout.SecurityContextLogoutHandler;
import javax.annotation.Resource;
import java.util.Map;
/**
* spring security配置
* <p>
* Created by surpass.wei@gmail.com on 2017/7/26.
*/
@Configuration
@EnableWebSecurity // 启用web权限(spring boot无须该注解)
@EnableGlobalMethodSecurity(prePostEnabled = true) //启用方法验证
@Profile("cas")
public class SecurityConfig extends WebSecurityConfigurerAdapter {
@Resource
private CasProperties casProperties;
/**
* 用户认证配置
*/
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
super.configure(auth);
auth.authenticationProvider(casAuthenticationProvider());
}
/**
* 请求授权配置
*/
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
// 允许所有用户访问的路径
.antMatchers("/html/**")
.permitAll()
.expressionHandler(httpSecurityExpressionHandler())
.anyRequest()
.authenticated()
.and()
.formLogin()
.loginProcessingUrl("/login")
.permitAll()
.and()
.rememberMe()
.tokenValiditySeconds(31536000)
.and()
.csrf()
.disable()
.logout()
.permitAll();
http.exceptionHandling().authenticationEntryPoint(casAuthenticationEntryPoint())
.and()
.addFilter(casAuthenticationFilter())
.addFilterBefore(casLogoutFilter(), LogoutFilter.class)
.addFilterBefore(singleSignOutFilter(), CasAuthenticationFilter.class);
http.csrf().disable(); //禁用CSRF
}
/**
* 指定service相关信息
*/
@Bean
public ServiceProperties serviceProperties() {
ServiceProperties serviceProperties = new ServiceProperties();
serviceProperties.setService(casProperties.getAppServerUrl() + casProperties.getAppLoginUrl());
serviceProperties.setAuthenticateAllArtifacts(true);
return serviceProperties;
}
@Bean
public SessionRegistry getSessionRegistry() {
return new SessionRegistryImpl();
}
@Bean
public DefaultWebSecurityExpressionHandler httpSecurityExpressionHandler() {
DefaultWebSecurityExpressionHandler expressionHandler = new DefaultWebSecurityExpressionHandler();
expressionHandler.setPermissionEvaluator(new MyPermissionEvaluator());
return expressionHandler;
}
@Bean
public DefaultWebSecurityExpressionHandler webSecurityExpressionHandler() {
final Map<String, DefaultWebSecurityExpressionHandler> expressionHandlers =
SpringContextUtil.getApplicationContext().getBeansOfType(DefaultWebSecurityExpressionHandler.class);
if (expressionHandlers.values().toArray()[0] != null) {
((DefaultWebSecurityExpressionHandler) expressionHandlers.values().toArray()[0]).setPermissionEvaluator(new MyPermissionEvaluator());
}
return (DefaultWebSecurityExpressionHandler) expressionHandlers.values().toArray()[0];
}
/**
* CAS认证过滤器
*/
@Bean
public CasAuthenticationFilter casAuthenticationFilter() throws Exception {
CasAuthenticationFilter casAuthenticationFilter = new CasAuthenticationFilter();
casAuthenticationFilter.setAuthenticationManager(authenticationManager());
casAuthenticationFilter.setFilterProcessesUrl(casProperties.getAppLoginUrl());
// 认证成功后的处理
//casAuthenticationFilter.setAuthenticationSuccessHandler(new SimpleUrlAuthenticationSuccessHandler("/html/user.html"));
return casAuthenticationFilter;
}
/**
* cas 认证 Provider
*/
@Bean
public CasAuthenticationProvider casAuthenticationProvider() {
CasAuthenticationProvider casAuthenticationProvider = new CasAuthenticationProvider();
casAuthenticationProvider.setAuthenticationUserDetailsService(customUserDetailsService());
//casAuthenticationProvider.setUserDetailsService(customUserDetailsService()); //这里只是接口类型,实现的接口不一样,都可以的。
casAuthenticationProvider.setServiceProperties(serviceProperties());
casAuthenticationProvider.setTicketValidator(cas20ServiceTicketValidator());
casAuthenticationProvider.setKey("casAuthenticationProviderKey");
return casAuthenticationProvider;
}
/**
* 用户自定义的AuthenticationUserDetailsService
*/
@Bean
public AuthenticationUserDetailsService<CasAssertionAuthenticationToken> customUserDetailsService() {
return new CustomUserDetailsService();
}
@Bean
public Cas20ServiceTicketValidator cas20ServiceTicketValidator() {
return new Cas20ServiceTicketValidator(casProperties.getCasServerUrl());
}
/**
* CAS认证的入口
*/
@Bean
public CasAuthenticationEntryPoint casAuthenticationEntryPoint() {
CasAuthenticationEntryPoint casAuthenticationEntryPoint = new CasAuthenticationEntryPoint();
casAuthenticationEntryPoint.setLoginUrl(casProperties.getCasServerLoginUrl());
casAuthenticationEntryPoint.setServiceProperties(serviceProperties());
return casAuthenticationEntryPoint;
}
/**
* CAS请求单点退出过滤器
*/
@Bean
public LogoutFilter casLogoutFilter() {
LogoutFilter logoutFilter = new LogoutFilter(casProperties.getCasServerLogoutUrl(), new SecurityContextLogoutHandler());
logoutFilter.setFilterProcessesUrl(casProperties.getAppLogoutUrl()); // 设置处理登出的路径
return logoutFilter;
}
/**
* CAS单点登出过滤器
*/
@Bean
public SingleSignOutFilter singleSignOutFilter() {
SingleSignOutFilter singleSignOutFilter = new SingleSignOutFilter();
singleSignOutFilter.setCasServerUrlPrefix(casProperties.getCasServerUrl());
singleSignOutFilter.setIgnoreInitConfiguration(true);
return singleSignOutFilter;
}
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(1)
每次提交完问题, 总是就可以自己找到解决方案, 是运气好吗? 折磨了我三天的问题终于解决了, 而导致这个问题的原因居然是spring boot(1.3.x)与cas(4.2.x)版本不兼容导致, 解决方案很简单, 升级spring boot版本到1.5.x, cas不用指定版本号(会根据spring-boot-starter-parent自动适应)