文章目录
0.0简介:
CAS是Central Authentication Service的缩写,中央认证服务,一种独立开放指令协议。CAS 是 耶鲁大学(Yale University)发起的一个开源项目,旨在为 Web 应用系统提供一种可靠的单点登录方法,CAS 在 2004 年 12 月正式成为 JA-SIG 的一个项目。
特点:
1、开源的企业级单点登录解决方案。
2、CAS Server 为需要独立部署的 Web 应用。
3、CAS Client 支持非常多的客户端(这里指单点登录系统中的各个 Web 应用),包括 Java, .Net, PHP, Perl, Apache, uPortal, Ruby 等。
4、CAS属于Apache 2.0许可证,允许代码修改,再发布(作为开源或商业软件)。
从结构上看,CAS 包含两个部分: CAS Server 和 CAS Client。CAS Server 需要独立部署,主要负责对用户的认证工作;CAS Client 负责处理对客户端受保护资源的访问请求,需要登录时,重定向到 CAS Server。图1 是 CAS 最基本的协议过程:
CAS Client 与受保护的客户端应用部署在一起,以 Filter 方式保护受保护的资源。对于访问受保护资源的每个 Web 请求,CAS Client 会分析该请求的 Http 请求中是否包含 Service Ticket,如果没有,则说明当前用户尚未登录,于是将请求重定向到指定好的 CAS Server 登录地址,并传递 Service (也就是要访问的目的资源地址),以便登录成功过后转回该地址。用户在第 3 步中输入认证信息,如果登录成功,CAS Server 随机产生一个相当长度、唯一、不可伪造的 Service Ticket,并缓存以待将来验证,之后系统自动重定向到 Service 所在地址,并为客户端浏览器设置一个 Ticket Granted Cookie(TGC),CAS Client 在拿到 Service 和新产生的 Ticket 过后,在第 5,6 步中与 CAS Server 进行身份核实,以确保 Service Ticket 的合法性。
在该协议中,所有与 CAS 的交互均采用 SSL 协议,确保,ST 和 TGC 的安全性。协议工作过程中会有 2 次重定向的过程,但是 CAS Client 与 CAS Server 之间进行 Ticket 验证的过程对于用户是透
明的。
另外,CAS 协议中还提供了 Proxy (代理)模式,以适应更加高级、复杂的应用场景,具体介绍可以参考 CAS 官方网站上的相关文档。 [1]
1.1 console-custom-core-imp工程的pom文件里加入引用
<dependency>
<groupId>org.jasig.cas.client</groupId>
<artifactId>cas-client-core</artifactId>
<version>3.5.0</version>
</dependency>
2.1 java代码编写
2.1.1 工程中增加添加url验证策略对象SimpleUrlPatternMatcher
import org.jasig.cas.client.authentication.UrlPatternMatcherStrategy;
import java.util.regex.Pattern;
public class SimpleUrlPatternMatcher implements UrlPatternMatcherStrategy {
private Pattern pattern;
@Override
public boolean matches(String s) {
return this.pattern.matcher(s).find();
}
@Override
public void setPattern(String s) {
this.pattern = Pattern.compile(s);
}
}
2.1.2 添加客户端配置对象
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.HttpServletRequestWrapperFilter;
import org.jasig.cas.client.validation.Cas30ProxyReceivingTicketValidationFilter;
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 java.util.HashMap;
import java.util.Map;
@Configuration
public class CasClientConfig {
//cas服务前缀
private static final String CAS_SERVER_URL_PREFIX="https://cas.somcompany.com:8443/cas/";
//cas服务登录地址
private static final String CAS_SERVER_LOGIN_URL="https://cas.somcompany.com:8443/cas/login";
//本机服务的名称
private static final String SERVER_NAME="http://app.somcompany.com:9099";
//登出过滤器
@Bean
public FilterRegistrationBean filterSingleRegistrationBean(){
System.out.println("----filterSingleRegistrationBean-----");
FilterRegistrationBean registrationBean = new FilterRegistrationBean();
registrationBean.setFilter(new SingleSignOutFilter());
//拦截所有的url
registrationBean.addUrlPatterns("/*");
Map<String,String> init = new HashMap<String,String>();
init.put("casServerUrlPrefix",CAS_SERVER_URL_PREFIX);
registrationBean.setInitParameters(init);
//设置调用顺序
registrationBean.setOrder(1);
return registrationBean;
}
//验证过滤器
@Bean
public FilterRegistrationBean filterValidRegistrationBean(){
System.out.println("----filterValidRegistrationBean-----");
FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
filterRegistrationBean.setFilter(new Cas30ProxyReceivingTicketValidationFilter());
filterRegistrationBean.addUrlPatterns("/*");
Map<String,String> init = new HashMap<String,String>();
init.put("casServerUrlPrefix",CAS_SERVER_URL_PREFIX);
init.put("serverName",SERVER_NAME);
//将登录用户信息放入session,默认为true
init.put("useSession","true");
filterRegistrationBean.setInitParameters(init);
filterRegistrationBean.setOrder(1);
return filterRegistrationBean;
}
//认证过滤器
@Bean
public FilterRegistrationBean filterAuthenticationRegistrationBean(){
System.out.println("----filterAuthenticationRegistrationBean-----");
FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
filterRegistrationBean.setFilter(new AuthenticationFilter());
filterRegistrationBean.addUrlPatterns("/*");
Map<String,String> init = new HashMap<String,String>();
init.put("casServerLoginUrl",CAS_SERVER_LOGIN_URL);
init.put("serverName",SERVER_NAME);
//当前服务退出的方法路径,我这里没写,先注释掉
// init.put("ignorePattern","");
//路径匹配策略
init.put("ignoreUrlPatternType","com.example.demo.config.SimpleUrlPatternMatcher");
filterRegistrationBean.setInitParameters(init);
filterRegistrationBean.setOrder(1);
return filterRegistrationBean;
}
//包装过滤器
@Bean
public FilterRegistrationBean filterWrapperRegistrationBean(){
System.out.println("----filterWrapperRegistrationBean-----");
FilterRegistrationBean filterRegistrationBean = new FilterRegistrationBean();
filterRegistrationBean.setFilter(new HttpServletRequestWrapperFilter());
filterRegistrationBean.addUrlPatterns("/*");
filterRegistrationBean.setOrder(1);
return filterRegistrationBean;
}
@Bean
public ServletListenerRegistrationBean servletListenerRegistrationBean(){
System.out.println("----servletListenerRegistrationBean-----");
ServletListenerRegistrationBean servletListenerRegistrationBean = new ServletListenerRegistrationBean();
servletListenerRegistrationBean.setListener(new SingleSignOutHttpSessionListener());
servletListenerRegistrationBean.setOrder(1);
return servletListenerRegistrationBean;
}
}
2.1.3 添加CAS单点登录处理controller
import org.jasig.cas.client.validation.AssertionImpl;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
@RestController("CASController")
@RequestMapping("/cas")
public class CASController {
/**
* 用户登录
*/
@RequestMapping(value = "/login", method = RequestMethod.GET)
public void login(HttpServletResponse httpServletResponse, HttpServletRequest request) throws Exception {
HttpSession session = request.getSession();
if (session != null && null != session.getAttribute("_const_cas_assertion_")) {
AssertionImpl assertionImpl = (AssertionImpl)session.getAttribute("_const_cas_assertion_");
String loginName = assertionImpl.getPrincipal().getName();
httpServletResponse.sendRedirect(generateSsoAddressHome(loginName));
}else {
throw new Exception("未查找到登录信息!");
}
}
/**
* 单点登录到首页
* @throws Exception
*/
static String generateSsoAddressHome(String loginName) throws Exception {
//此处为单点登录逻辑
return ssoAddress;
}
}
2.1.4 放行刚编写的接口的登录验证
application.yml中 yn.login-auth-filter.exclutionsList中增加:
- /cas/login
3.1验证
3.1.1浏览器中输入:
http://app.somecompany.com:9099/console/cas/login
3.1.2会发现浏览器重定向到CAS的登录页:
3.1.3输入用户名密码登录后会重定向到app页面
图略