我正在开发一个具有angular2前端和spring引导后端的应用程序。对于身份验证我使用CAS。单点登录工作正常,但单点注销无法正常工作,甚至没有重定向到cas / logout端点。(我正在从角应用程序发送一个POST给我的spring boot app / logout url)
CAS版本 - 4.2.2
CAS客户核心 - 3.4
我关注http://docs.spring.io/spring-security/site/migrate/current/3-to-4/html5/migrate-3-to-4-jc.html#m3to4-filter-urls-cas并对身份验证过滤器和注销过滤器进行了必要的更改。但我仍然无法确定问题。任何帮助深表感谢。
安全配置
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true, jsr250Enabled = true)
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
@Autowired
private AuthProperties properties;
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.addFilterAfter(csrfHeaderFilter(), CsrfFilter.class)
.addFilterBefore(requestSingleLogoutFilter(), LogoutFilter.class)
.addFilterBefore(singleSignOutFilter(), CasAuthenticationFilter.class)
.addFilterBefore(casAuthenticationFilter(), BasicAuthenticationFilter.class)
.exceptionHandling()
.authenticationEntryPoint(casAuthenticationEntryPoint())
.and()
.logout()
.logoutUrl("/logout")
.invalidateHttpSession(true)
.deleteCookies("JSESSIONID")
.permitAll()
.and()
.authorizeRequests()
.antMatchers("//**").authenticated()
.antMatchers("/test").permitAll()
.and()
.csrf()
.csrfTokenRepository(csrfTokenRepository());
}
/***
* Service Properties refer to the application which is being authenticated
* Typically in this case, the service is the authentication engine or auth app
*/
@Bean
public ServiceProperties serviceProperties() {
ServiceProperties sp = new ServiceProperties();
sp.setService(properties.getAppServiceSecurity());
sp.setArtifactParameter("casTicket");
sp.setAuthenticateAllArtifacts(true);
sp.setSendRenew(false);
return sp;
}
@Bean
public CasAuthenticationProvider casAuthenticationProvider() throws Exception {
CasAuthenticationProvider casAuthenticationProvider = new CasAuthenticationProvider();
casAuthenticationProvider.setAuthenticationUserDetailsService(userService());
casAuthenticationProvider.setServiceProperties(serviceProperties());
if (properties.isCasProxyTicket()) {
casAuthenticationProvider.setTicketValidator(cas30ServiceProxyTicketValidator());
casAuthenticationProvider.setStatelessTicketCache(ehManager());
} else {
casAuthenticationProvider.setTicketValidator(cas30ServiceTicketValidator());
}
casAuthenticationProvider.setKey(properties.getProviderKey());
return casAuthenticationProvider;
}
@Bean
public SessionAuthenticationStrategy sessionStrategy() {
SessionAuthenticationStrategy sessionStrategy = new SessionFixationProtectionStrategy();
return sessionStrategy;
}
@Bean
public Cas30ServiceTicketValidator cas30ServiceTicketValidator() {
return new Cas30ServiceTicketValidator(properties.getCasUrlPrefix());
}
@Bean
public CasAuthenticationFilter casAuthenticationFilter() throws Exception {
CasAuthenticationFilter casAuthenticationFilter = new CasAuthenticationFilter();
casAuthenticationFilter.setAuthenticationManager(authenticationManager());
casAuthenticationFilter.setSessionAuthenticationStrategy(sessionStrategy());
casAuthenticationFilter.setProxyGrantingTicketStorage(pgtStorage());
casAuthenticationFilter.setFilterProcessesUrl("/login/cas");
casAuthenticationFilter.setProxyReceptorUrl(properties.getCasProxyReceptor());
return casAuthenticationFilter;
}
@Bean
public CasAuthenticationEntryPoint casAuthenticationEntryPoint() {
CasAuthenticationEntryPoint casAuthenticationEntryPoint = new TBXCasAuthenticationEntryPoint();
casAuthenticationEntryPoint.setLoginUrl(properties.getCasLoginUrl());
casAuthenticationEntryPoint.setServiceProperties(serviceProperties());
return casAuthenticationEntryPoint;
}
@Bean
public LogoutFilter requestSingleLogoutFilter() {
StringBuffer stringBuffer = new StringBuffer("");
stringBuffer.append(properties.getCasLogoutUrl());
LogoutFilter logoutFilter = new LogoutFilter("https://localhost:9443/cas/logout", new SecurityContextLogoutHandler());//env.getRequiredProperty(CAS_URL_LOGOUT) + "?service="+ env.getRequiredProperty(APP_SERVICE_HOME)
logoutFilter.setFilterProcessesUrl("/logout");
return logoutFilter;
}
@Bean
public SingleSignOutFilter singleSignOutFilter() {
SingleSignOutFilter filter = new SingleSignOutFilter();
filter.setArtifactParameterName(Protocol.CAS3.getArtifactParameterName());
filter.setCasServerUrlPrefix("https://localhost:9443/cas");
filter.setIgnoreInitConfiguration(true);
return filter;
}
@Bean
public Filter csrfHeaderFilter() {
return new OncePerRequestFilter() {
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
CsrfToken csrf = (CsrfToken) request.getAttribute(CsrfToken.class.getName());
if (csrf != null) {
Cookie cookie = WebUtils.getCookie(request, "XSRF-TOKEN");
if (cookie != null) {
} else {
}
String token = csrf.getToken();
if (cookie == null || token != null && !token.equals(cookie.getValue())) {
cookie = new Cookie("XSRF-TOKEN", token);
cookie.setPath("/");
response.addCookie(cookie);
}
}
filterChain.doFilter(request, response);
}
};
}
@Bean
public CsrfTokenRepository csrfTokenRepository() {
HttpSessionCsrfTokenRepository repository = new HttpSessionCsrfTokenRepository();
repository.setHeaderName("X-XSRF-TOKEN");
return repository;
}
/**
* configure via WebSecurity provides the fonts, images, scripts, styles and views to be removed
* from the security features, because, access to these scripts is a must regarding the user experience
**/
@Override
public void configure(WebSecurity web) throws Exception {
web.ignoring()
.antMatchers("/fonts*//**")
.antMatchers("/images1*//**")
.antMatchers("/scripts*//**")
.antMatchers("/styles*//**")
.antMatchers("/views*//**")
.antMatchers("/i18n*//**");
}
@Bean
public UserPrincipleHandler userService() {
UserPrincipleHandler userPrincipleServiceHanlder = new UserPrincipleHandler();
return userPrincipleServiceHanlder;
}
@Bean
public RequestContextListener requestContextListener() {
return new RequestContextListener();
}
@Bean
public RequestContextFilter requestContextFilter() {
return new RequestContextFilter();
}
@Bean
public ServiceAuthenticationDetailsSource serviceAuthenticationDataSource() {
ServiceAuthenticationDetailsSource serviceDetailSource = new ServiceAuthenticationDetailsSource(serviceProperties());
return serviceDetailSource;
}
@Bean
public SimpleUrlAuthenticationFailureHandler simpleUrlAuthentication() {
SimpleUrlAuthenticationFailureHandler failureHandler = new SimpleUrlAuthenticationFailureHandler();
failureHandler.setDefaultFailureUrl(properties.getCasFailureUrl());
return failureHandler;
}
@Bean
public ProxyList proxyChainList() {
List<String> list = properties.getProxyList();
String[] stringArray = Arrays.copyOf(list.toArray(), list.size(), String[].class);
List<String[]> urls = new ArrayList<String[]>();
urls.add(stringArray);
ProxyList proxyList = new ProxyList(urls);
return proxyList;
}
@Bean
public ProxyGrantingTicketStorageImpl pgtStorage() {
ProxyGrantingTicketStorageImpl pgtImpl = new ProxyGrantingTicketStorageImpl();
return pgtImpl;
}
@Bean
public SpringCacheBasedTicketCache ehManager() throws Exception {
SpringCacheBasedTicketCache ehmanager = new SpringCacheBasedTicketCache(cacheMap());
return ehmanager;
}
@Bean
public ConcurrentMapCache cacheMap() {
ConcurrentMapCache conCacheMap = new ConcurrentMapCache("casTickets");
conCacheMap.put("casTickets", 50);
return conCacheMap;
}
@Bean
public Cas30ProxyTicketValidator cas30ServiceProxyTicketValidator() {
Cas30ProxyTicketValidator validator = new Cas30ProxyTicketValidator(properties.getCasUrlPrefix());//env.getRequiredProperty(CAS_URL_PREFIX)
StringBuffer stringBuffer = new StringBuffer("");
stringBuffer.append(properties.getAppServiceHome()).append(properties.getCasProxyReceptor());
validator.setProxyCallbackUrl(stringBuffer.toString());//env.getRequiredProperty(APP_SERVICE_HOME)+"login/cas/proxyreceptor"
validator.setProxyGrantingTicketStorage(pgtStorage());
validator.setAllowedProxyChains(proxyChainList());
validator.setAcceptAnyProxy(false);
return validator;
}
}