cas是Central Authentication Service的简写.提供中央认证服务,实现企业级单点登录.详细参考:https://www.apereo.org/projects/cas .下面是入门测试
一.客户端核心配置.
package org.exam.config;
import org.jasig.cas.client.validation.Cas20ProxyTicketValidator;
import org.jasig.cas.client.validation.TicketValidator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.context.support.ReloadableResourceBundleMessageSource;
import org.springframework.core.env.Environment;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.cas.ServiceProperties;
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.method.configuration.GlobalMethodSecurityConfiguration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import javax.annotation.Resource;
/**
* Created by on 16/6/18.
*/
@Configuration
public class SecurityConfig {
@Configuration
@EnableWebSecurity
@PropertySource("classpath:config.properties")
protected static class WebSecurityConfig extends WebSecurityConfigurerAdapter {
@Resource
private Environment env;
@Bean
public ReloadableResourceBundleMessageSource messageSource() {//本地化(不完全)
ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource();
messageSource.setBasename("classpath:org/springframework/authentication/messages");
return messageSource;
}
//配置ServiceProperties
@Bean
public ServiceProperties serviceProperties() {
ServiceProperties serviceProperties = new ServiceProperties();
serviceProperties.setService(env.getProperty("cas.service"));
return serviceProperties;
}
//配置认证切入点
@Bean
public CasAuthenticationEntryPoint authenticationEntryPoint() {
CasAuthenticationEntryPoint authenticationEntryPoint = new CasAuthenticationEntryPoint();
authenticationEntryPoint.setServiceProperties(serviceProperties());
authenticationEntryPoint.setLoginUrl(env.getProperty("cas.loginUrl"));
return authenticationEntryPoint;
}
//配置从cas认证回来的请求拦截器
@Bean
public CasAuthenticationFilter authenticationFilter() throws Exception {
CasAuthenticationFilter authenticationFilter = new CasAuthenticationFilter();
authenticationFilter.setAuthenticationManager(authenticationManager());
authenticationFilter.setFilterProcessesUrl(env.getProperty("cas.processesUrl"));
return authenticationFilter;
}
//提供用户数据源
@Autowired
private UserDetailsService userDetailsService;
//断言
@Bean
public TicketValidator ticketValidator(){
return new Cas20ProxyTicketValidator(env.getProperty("cas.serverUrlPrefix"));
}
//配置认证提供者
@Bean
public CasAuthenticationProvider authenticationProvider() {
CasAuthenticationProvider authenticationProvider = new CasAuthenticationProvider();
authenticationProvider.setServiceProperties(serviceProperties());
authenticationProvider.setUserDetailsService(userDetailsService);
authenticationProvider.setTicketValidator(ticketValidator());
authenticationProvider.setKey(env.getProperty("cas.key"));
return authenticationProvider;
}
//将认证提供者加入到认证管理器
@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(authenticationProvider());
}
//配置
@Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests().anyRequest().authenticated()
.and().logout().logoutUrl("/logout").logoutSuccessUrl(env.getProperty("cas.logoutUrl")).permitAll()
.and().exceptionHandling().accessDeniedPage("/exclude/403").authenticationEntryPoint(authenticationEntryPoint())
.and().addFilterAt(authenticationFilter(), CasAuthenticationFilter.class);
}
//配置忽略ant表达式
@Override
public void configure(WebSecurity web) throws Exception {
web.ignoring().antMatchers("/static/**", "/exclude/**");
}
//暴露AuthenticationManager注册成Bean供@EnableGlobalMethodSecurity使用
@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
}
@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
protected static class MethodSecurityConfig extends GlobalMethodSecurityConfiguration {
}
}
#cas.service=https://localhost:8443/cas-client/login/cas
cas.service=http://localhost:8080/cas-client/login/cas
cas.processesUrl=/login/cas
cas.loginUrl=https://localhost:443/cas-server/login
cas.serverUrlPrefix=https://localhost:443/cas-server
cas.key=123456
二.服务端必须配置ssl(可以不启用客户端认证)
可能遇到的问题:
1.从cas服务端到cas客户端必须使用https,从cas客户端到cas服务端使用http也可以.
2.断言客户端抛错java.lang.RuntimeException: javax.net.ssl.SSLHandshakeException: java.security.cert.CertificateException: No name matching localhost found
解决思路:将cas服务端的keystore文件的CN设为localhost
d:\jdk8\bin\keytool -genkeypair -alias server -keystore server.p12 -storetype PKCS12 -keyalg RSA -storepass changeit -keypass changeit -validity 365 -dname "CN=localhost, OU=test, O=test, L=TH, ST=GZ, C=CN"
3.客户端抛错java.lang.RuntimeException: javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target
解决思路(http://stackoverflow.com/questions/9619030/resolving-javax-net-ssl-sslhandshakeexception-sun-security-validator-validatore) :将cas服务端的证书导入到%JAVA_HOME%\lib\security\cacerts
a.查看个修改前的cacerts:d:\jdk8\bin\keytool -list -keystore "d:/jdk8/jre/lib/security/cacerts"
b.备份一下cacerts,将cacerts命令为cacerts.160618
c:
导出证书:
d:\jdk8\bin\keytool -exportcert -alias server -file server.cer -keystore server.p12 -storetype PKCS12 -storepass changeit
导入到cacerts:
d:\jdk8\bin\keytool -import -noprompt -trustcacerts -alias server -file server.cer -keystore cacerts -storepass changeit
e:再次运行d:\jdk8\bin\keytool -list -keystore "d:/jdk8/jre/lib/security/cacerts"
查看导入结果,并和之前的查看进行对比,确认是否导入