文章目录
一、准备
jdk版本最低要求1.8
服务端使用cas-overlay-template,版本是5.3,下载地址,下载解压完成后,作为maven项目导入idea,如图所示:
不需要任何开发,执行maven package命令,即可打包生成cas.war文件,放在tomcat的wenapps下,直接启动,或者直接在idea中配置tomcat启动,启动完成之后,可以看到登录页。
客户端使用springboot集成CAS,创建springboot项目。我这里使用的是2.2.2.RELEASE版本
二、配置
服务端使用的是overlay项目,可以通过创建同名文件,来覆盖模板的文件,从而达到自定义开发服务端的目的。
注意:这里的同名文件,指的是编译之后的全路径相同,名称相同。比如,我在项目中创建一个src的目录,在这个目录下,有一个spring.factories的文件,编译时,我的文件会覆盖的同路径下的spring.factories同名文件,使用的是我的文件,而不是模板中的文件。
如果想服务端支持https,请看这位大佬
如果不使用http,可以在按照上面的方法创建一个services目录下的HTTPSandIMAPS-10000001.json的同名文件,从编译之后的WEB-INF/services目录下,全部复制到新建的文件中,如下图所示,在箭头所指位置添加 http 字符串,记得添加 | 符号。
复制模板文件application.properties,到src中,修改端口号,并插入以下两行配置,即可支持http访问。
cas.tgc.secure=false
cas.serviceRegistry.initFromJson=true
客户端配置文件如下:
pom.xml依赖
<!--CAS客户端集成-->
<dependency>
<groupId>net.unicon.cas</groupId>
<artifactId>cas-client-autoconfig-support</artifactId>
<version>1.5.0-GA</version>
</dependency>
application.yml
cas:
server-url-prefix: http://localhost:8080/cas #CAS项目地址
server-login-url: ${cas.server-url-prefix}/login #CAS登录地址
client-host-url: http://localhost #本项目地址
validation-type: cas #cas,cas3,SAML三种选择
validation-type这个属性,除开SAML不说,要想在获取到自定义信息(这个得修改服务端,自定义返回消息handler,还是看这位大佬,以及之后如何把自定义的handler注册到服务端中,还是看这位),必须是cas3(不配置默认是CAS3),才能返回attributes信息。如果是cas,只能返回当前用户名。
过滤器配置
package cn.he.develop.config;
import com.alibaba.fastjson.JSONObject;
import net.unicon.cas.client.configuration.CasClientConfigurerAdapter;
import net.unicon.cas.client.configuration.EnableCasClient;
import org.jasig.cas.client.authentication.AttributePrincipal;
import org.jasig.cas.client.authentication.AuthenticationFilter;
import org.jasig.cas.client.session.SingleSignOutFilter;
import org.jasig.cas.client.session.SingleSignOutHttpSessionListener;
import org.jasig.cas.client.util.AbstractCasFilter;
import org.jasig.cas.client.util.HttpServletRequestWrapperFilter;
import org.jasig.cas.client.validation.Assertion;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.ServletListenerRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.Ordered;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpSession;
import java.security.Principal;
import java.util.Map;
@Configuration
@Controller
@EnableCasClient
public class CasConfig extends CasClientConfigurerAdapter {
@Value("${cas.server-url-prefix}")
private String CAS_URL;
@Value("${cas.client-host-url}")
private String APP_URL;
@Override
public void configureAuthenticationFilter(FilterRegistrationBean authenticationFilter) {
super.configureAuthenticationFilter(authenticationFilter);
//authenticationFilter.getInitParameters().put("authenticationRedirectStrategyClass","com.patterncat.CustomAuthRedirectStrategy");
}
@Bean
public ServletListenerRegistrationBean servletListenerRegistrationBean(){
ServletListenerRegistrationBean listenerRegistrationBean = new ServletListenerRegistrationBean();
listenerRegistrationBean.setListener(new SingleSignOutHttpSessionListener());
listenerRegistrationBean.setOrder(Ordered.HIGHEST_PRECEDENCE);
return listenerRegistrationBean;
}
/**
* 单点登录退出
*
* @return
*/
@Bean
public FilterRegistrationBean singleSignOutFilter() {
FilterRegistrationBean registrationBean = new FilterRegistrationBean();
registrationBean.setFilter(new SingleSignOutFilter());
registrationBean.addUrlPatterns("/*");
registrationBean.addInitParameter("casServerUrlPrefix", CAS_URL);
registrationBean.setName("CAS Single Sign Out Filter");
registrationBean.setOrder(1);
return registrationBean;
}
/**
* 单点登录认证
* @return
*/
@Bean
public FilterRegistrationBean AuthenticationFilter() {
FilterRegistrationBean registrationBean = new FilterRegistrationBean();
registrationBean.setFilter(new AuthenticationFilter());
registrationBean.addUrlPatterns("/*");
registrationBean.setName("CAS Filter");
registrationBean.addInitParameter("casServerLoginUrl", CAS_URL);
registrationBean.addInitParameter("serverName", APP_URL);
registrationBean.setOrder(3);
return registrationBean;
}
/**
* 单点登录请求包装
* @return
*/
@Bean
public FilterRegistrationBean httpServletRequestWrapperFilter(){
FilterRegistrationBean registrationBean = new FilterRegistrationBean();
registrationBean.setFilter(new HttpServletRequestWrapperFilter());
registrationBean.addUrlPatterns("/*");
registrationBean.setName("CAS HttpServletRequest Wrapper Filter");
registrationBean.setOrder(5);
return registrationBean;
}
//登出
@RequestMapping("/logout")
public String logout(HttpSession session){
session.invalidate();
return "redirect:"+CAS_URL+"/logout?service="+APP_URL+"/admin/index.html";
}
/**
* 从kweb-cas中获取登录信息
* @param request
* @return
*/
@GetMapping(value = {"/loginUserInfo"})
@ResponseBody
public String loginUserInfo(HttpServletRequest request){
Assertion assertion = (Assertion) request.getSession().getAttribute(AbstractCasFilter.CONST_CAS_ASSERTION);
if(assertion!= null){
AttributePrincipal principal = assertion.getPrincipal();
String s = JSONObject.toJSONString(assertion);
//获取自定义返回值的数据
Principal principal2 = (AttributePrincipal) request.getUserPrincipal();
if (request.getUserPrincipal() != null) {
if (principal2 instanceof AttributePrincipal) {
//cas传递过来的数据
Map<String,Object> result =( (AttributePrincipal)principal).getAttributes();
for(Map.Entry<String, Object> entry :result.entrySet()) {
String key = entry.getKey();
Object val = entry.getValue();
System.out.printf("%s:%s\r\n",key,val);
}
}
}
return s;
}else {
return null;
}
}
}
至此,项目配置完成。
三、遇到的问题
1.无法返回自定义attributes信息
validation-type: cas,配置了cas。
cas的登录流程是登录之后,拿到ticket,然后再去验证ticket是否正确,正确则返回认证信息。在cas的jar包中,Cas30ProxyReceivingTicketValidationFilter,Cas20ProxyReceivingTicketValidationFilter,这两个类中的Cas30ServiceTicketValidator,Cas20ServiceTicketValidator是用来验证ticket的。 Cas20ServiceTicketValidator中配置的验证url前缀是“serviceValidate”,而Cas30ProxyReceivingTicketValidationFilter中配置的验证url前缀是“p3/serviceValidate”,配置的过滤器不同,验证的url也就不同,加上的p3的前缀,服务端会认为是使用3.0协议,会返回自定义的消息,就是attributes中的消息
2.服务端无法使用自己的文件,编译之后还是使用模板的代码
文件的覆盖,一定是要同路径同名称的,也就是编译之后的路径名称相同,自己写的文件,会覆盖掉模板中的文件
3.在过滤器中自己配置了Cas30ProxyReceivingTicketValidationFilter,没有生效
模板会根据你的配置,默认注册一个Cas30ProxyReceivingTicketValidationFilter或者是Cas20ProxyReceivingTicketValidationFilter,这个filter的优先级比你自己配置的高,执行到这个filter,就不会执行到后边自己配置的。