windows 7 64bit
spring boot:1.4.0.RELEASE
spring security:4.1.0.RELEASE
CAS:4.1.3
nginx:随便
以命令方式进入目录%TOMCAT_HOME%,输入如下命令:
keytool -genkey -alias tomcat_key -keyalg RSA -storepass changeit -keystore server.keystore -validity 3600
注意: -storepass 与 -validity 可以根据需要更改
用户名输入域名,如:test.cas.com,其它全部以Enter跳过,最后确认,此时会在%TOMCAT_HOME%下生成server.keystore文件
这步对于Tomcat的SSL配置不是必须,但对于CAS SSO是必须的,否则会出现如下错误:
edu.yale.its.tp.cas.client.CASAuthenticationException: Unable to validate ProxyTicketValidate.
导入过程分2步,第一步是导出证书,第二步是导入到证书信任库,命令如下:
keytool -export -trustcacerts -alias tomcat_key -file server.cer -keystore server.keystore -storepass changeit
keytool -import -trustcacerts -alias tomcat_key -file server.cer -keystore D:/”Program Files”/Java/jdk1.8.0_60/jre/lib/security/cacerts -storepass changeit
其它有用keytool命令(列出信任证书库中所有已有证书,删除库中某个证书):
keytool -list -keystore %JAVA_HOME%/jre/lib/security/cacerts >t.txt
keytool -delete -trustcacerts -alias tomcat_key -keystore %JAVA_HOME%/jre/lib/security/cacerts -storepass changeit
配置server.xml:
解压,使用maven命令mvn package对cas进行编译打包,这里可能会出现2个问题:
a.单元测试不通过==》尝试加上-Dmaven.test.skip=true跳过;
b.编译到一半编译不过==》进入cas-server-core,执行命令mvn install -Dmaven.test.skip=true先将core编译为jar包后,再进行。
3.将打包好的cas-server-webapp下的war包复制到tomcat下,运行tomcat先试试吧;
注意:如果觉得麻烦,可以上网搜索cas-server-webapp,使用别人打好的war包
4.将war包放入tomcat的webapps目录下即可
1.修改%tomcathome%\webapps\cas\WEB-INF中deployerConfigContext.xml:
注意:配置中使用mysql数据库,c3p0连接池,需要引入相关的jar包
将c3p0-0.9.1.1.jar,cas-server-support-jdbc-4.1.3.jar,mysql-connector-java-5.1.32.jar放入%tomcathome%\webapps\cas\WEB-INF\lib中
2.修改%tomcathome%\webapps\cas\WEB-INF\classes\services\Apereo-10000002.json
"serviceId" : "^http.*",
修改%tomcathome%\webapps\cas\WEB-INF\spring-configuration\ticketExpirationPolicies.xml
注意:根据需要进行修改
至此,所需配置完成,浏览器:http://test.cas.com/cas,进行登陆测试!
注意:test.cas.com为CAS 服务所在机器的域名(如无进行域名配置,可以修改本机hosts,127.0.0.1 test.cas.com达到测试效果)
org.springframework.boot
spring-boot-starter-security
org.springframework.security
spring-security-data
org.springframework.security
spring-security-cas
@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
@Inject
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(casAuthenticationProvider());
}
@Override
public void configure(WebSecurity web) throws Exception {
web.ignoring()
.antMatchers(HttpMethod.OPTIONS, "/**")
.antMatchers("/app/**/*.{js,html}")
.antMatchers("/bower_components/**")
.antMatchers("/i18n/**")
.antMatchers("/content/**")
.antMatchers("/test/**")
;
}
@Bean
public PasswordEncoder passwordEncoder() {
return new StandardPasswordEncoder("tnappsk1234");
}
@Bean
public ServiceProperties serviceProperties() {
ServiceProperties sp = new ServiceProperties();
//从cas server获取st后重定向的url,casAuthenticationFilter进行捕获,默认以/login/cas结尾
String fstr = "http://test.tn.com/login/cas";
sp.setService(fstr);
sp.setSendRenew(false);
return sp;
}
@Bean
public CasAuthenticationEntryPoint casAuthenticationEntryPoint(){
CasAuthenticationEntryPoint ep = new CasAuthenticationEntryPoint();
ep.setServiceProperties(serviceProperties());
//cas server 登陆路径
ep.setLoginUrl("https://test.cas.com:9443/cas/login");
return ep;
}
@Bean
public CasAuthenticationProvider casAuthenticationProvider(){
CasAuthenticationProvider pro = new CasAuthenticationProvider();
pro.setServiceProperties(serviceProperties());
pro.setAuthenticationUserDetailsService(customUserDetailsService());
pro.setTicketValidator(cas20ServiceTicketValidator());
pro.setKey("an_id_for_this_auth_provider_only");
return pro;
}
@Bean
public Cas20ServiceTicketValidator cas20ServiceTicketValidator() {
//cas server路径
return new Cas20ServiceTicketValidator("https://test.cas.com:9443/cas");
}
@Bean
public AuthenticationUserDetailsService customUserDetailsService() {
Set admins = new HashSet();
String adminUserName = "admin";
admins.add("admin");
if (adminUserName != null && !adminUserName.isEmpty()) {
admins.add(adminUserName);
}
return new CustomUserDetailsService(admins);
}
@Bean
public CasAuthenticationFilter casAuthenticationFilter() throws Exception{
CasAuthenticationFilter af = new CasAuthenticationFilter();
af.setSessionAuthenticationStrategy(sessionStrategy());
af.setAuthenticationManager(authenticationManager());
return af;
}
@Bean
public SessionAuthenticationStrategy sessionStrategy() {
SessionAuthenticationStrategy sessionStrategy = new SessionFixationProtectionStrategy();
return sessionStrategy;
}
@Bean
public SingleSignOutFilter singleSignOutFilter() {
SingleSignOutFilter singleSignOutFilter = new SingleSignOutFilter();
singleSignOutFilter.setIgnoreInitConfiguration(true);
singleSignOutFilter.setCasServerUrlPrefix("https://test.cas.com:9443/cas");
return singleSignOutFilter;
}
@Bean
public LogoutFilter requestCasGlobalLogoutFilter() {
LogoutFilter logoutFilter = new LogoutFilter("https://test.cas.com:9443/cas/logout?service=http://test.tn.com", new SecurityContextLogoutHandler());
logoutFilter.setFilterProcessesUrl("/api/logout");
logoutFilter.setLogoutRequestMatcher(new AntPathRequestMatcher("/api/logout", "POST"));
return logoutFilter;
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http.exceptionHandling().authenticationEntryPoint(casAuthenticationEntryPoint())
.and().addFilter(casAuthenticationFilter())
.addFilterBefore(singleSignOutFilter(), CasAuthenticationFilter.class)
.addFilterBefore(requestCasGlobalLogoutFilter(), LogoutFilter.class);
http
.csrf().disable()
.headers()
.frameOptions()
.disable()
.and()
.authorizeRequests()
.antMatchers("/api/register").denyAll()
.antMatchers("/api/activate").permitAll()
.antMatchers("/api/content-items/category").permitAll()
.antMatchers("/api/authenticate").permitAll()
.antMatchers("/api/account/reset_password/init").permitAll()
.antMatchers("/api/account/reset_password/finish").permitAll()
.antMatchers("/api/profile-info").permitAll()
.antMatchers("/api/**").authenticated()
.antMatchers("/management/**").hasAuthority(AuthoritiesConstants.ADMIN)
.antMatchers("/v2/api-docs/**").permitAll()
.antMatchers("/swagger-resources/configuration/ui").permitAll()
.antMatchers("/swagger-ui/index.html").hasAuthority(AuthoritiesConstants.ADMIN);
}
@Bean
public SecurityEvaluationContextExtension securityEvaluationContextExtension() {
return new SecurityEvaluationContextExtension();
}
}
注意:密码passwordEncoder(),需要配置成与cas一致,使用MD5,这里配置有误
主要:CasAuthenticationFilter,CasAuthenticationEntryPoint,CasAuthenticationProvider的配置,
具体可以参考Spring Security官方文档CAS Authentication部分:
http://docs.spring.io/spring-security/site/docs/4.2.0.RELEASE/reference/htmlsingle/#cas
使用redis做http session的缓存,这样当从cas server 重定向回某类应用的service url(下有多个机子组成集群)时,可以指定同一个域名,这样session就实现了共享。
org.springframework.boot
spring-boot-starter-redis
org.springframework.session
spring-session-data-redis
@Configuration
@EnableRedisHttpSession
public class RedisSessionConfig {
/**
* 修改数据在redis中的存储方式,方便调试
* @Title: sessionRedisTemplate
* @Description: TODO
* @param connectionFactory
* @return
* @return: RedisTemplate
http{
upstream tn {
server test.tn.com:6900;
server test.tn.com:6901;
}
server{
listen 80;
location / {
proxy_pass http://tn;
}
}
127.0.0.1 test.tn.com //webapp
127.0.0.1 test.cas.com //cas server
start nginx启动
浏览器中,访问http://test.tn.com/xxx/xxx(受管控方法),跳转到Cas Server,登陆验证身份后,重定向回之前的url,不断刷新,通过观察日子,请求分发到不同的webapp