除了在web.xml添加CAS内置的filter外(具体看配置web.xml),我们需要撰写自己支持CAS集成的客户化包。大致思路如下:
@Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest)servletRequest;
HttpServletResponse response = (HttpServletResponse)servletResponse;
HttpSession session = request.getSession();
//在session中自定义一个参数,以它来校验是否完成过自动登陆
Object user_login = session.getAttribute(AURORA_USER_LOGIN);
if (user_login != null){
//登陆过,就继续执行其他filter
filterChain.doFilter(request, response);
return;
}
//通过CAS的API获得登陆账号
String loginName = AssertionHolder.getAssertion().getPrincipal().getName();
try {
//执行本系统的登陆。跟平常同时校验用户名和密码不同,这里只有用户名。
executeLoginProc(request,response,loginName);
} catch (Exception e) {
logger.log(Level.SEVERE, "executeLoginProc error:", e);
return;
}
//登陆成功
session.setAttribute(AURORA_USER_LOGIN, Boolean.TRUE);
//跳转到登陆成功后的页面
response.sendRedirect(roleSelectPageUrl);
}
把这个class打包成一个jar拷贝到应用的WEB-INF/lib目录中。
如果有兴趣,还可以简单了解下org.jasig.cas.client.authentication.AuthenticationFilter这个CAS内置filter的功能
public final void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest)servletRequest;
HttpServletResponse response = (HttpServletResponse)servletResponse;
HttpSession session = request.getSession(false);
//检查自定义属性"_const_cas_assertion_"
Assertion assertion = session != null ? (Assertion)session.getAttribute("_const_cas_assertion_") : null;
if (assertion != null) {
//已经成功登陆过CAS
filterChain.doFilter(request, response);
return;
}
//拿到url,并检查url参数中的ticket是否有效
String serviceUrl = constructServiceUrl(request, response);
String ticket = CommonUtils.safeGetParameter(request, getArtifactParameterName());
boolean wasGatewayed = this.gatewayStorage.hasGatewayedAlready(request, serviceUrl);
if ((CommonUtils.isNotBlank(ticket)) || (wasGatewayed)) {
//ticket有效
filterChain.doFilter(request, response);
return;
}
this.log.debug("no ticket and no assertion found");
String modifiedServiceUrl;
String modifiedServiceUrl;
if (this.gateway) {
this.log.debug("setting gateway attribute in session");
modifiedServiceUrl = this.gatewayStorage.storeGatewayInformation(request, serviceUrl);
} else {
modifiedServiceUrl = serviceUrl;
}
if (this.log.isDebugEnabled()) {
this.log.debug("Constructed service url: " + modifiedServiceUrl);
}
String urlToRedirectTo = CommonUtils.constructRedirectUrl(this.casServerLoginUrl, getServiceParameterName(), modifiedServiceUrl, this.renew, this.gateway);
if (this.log.isDebugEnabled()) {
this.log.debug("redirecting to \"" + urlToRedirectTo + "\"");
}
//重定向到cas的登陆页面
response.sendRedirect(urlToRedirectTo);
}
在应用WEB-INF/web.xml添加filter的内容,效果如下所示
<!-- ======================== 单点登录开始 ======================== -->
<!-- 用于单点退出,该过滤器用于实现单点登出功能,可选配置-->
<listener>
<listener-class>org.jasig.cas.client.session.SingleSignOutHttpSessionListener</listener-class>
</listener>
<!-- 该过滤器用于实现单点登出功能,可选配置。 -->
<filter>
<filter-name>CAS Single Sign Out Filter</filter-name>
<filter-class>org.jasig.cas.client.session.SingleSignOutFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>CAS Single Sign Out Filter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- 该过滤器负责用户的认证工作,必须启用它 -->
<filter>
<filter-name>CASFilter</filter-name>
<filter-class>org.jasig.cas.client.authentication.AuthenticationFilter</filter-class>
<init-param>
<param-name>casServerLoginUrl</param-name>
<param-value>https://sso.:8080/cas/login</param-value>
<!--这里的server是服务端的IP-->
</init-param>
<init-param>
<param-name>serverName</param-name>
<param-value>https://sso.:8080</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CASFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- 该过滤器负责对Ticket的校验工作,必须启用它 -->
<filter>
<filter-name>CAS Validation Filter</filter-name>
<filter-class>
org.jasig.cas.client.validation.Cas20ProxyReceivingTicketValidationFilter</filter-class>
<init-param>
<param-name>casServerUrlPrefix</param-name>
<param-value>https://sso.:8080/cas</param-value>
</init-param>
<init-param>
<param-name>serverName</param-name>
<param-value>https://sso.:8080</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CAS Validation Filter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!--
该过滤器负责实现HttpServletRequest请求的包裹,
比如允许开发者通过HttpServletRequest的getRemoteUser()方法获得SSO登录用户的登录名,可选配置。
-->
<filter>
<filter-name>CAS HttpServletRequest Wrapper Filter</filter-name>
<filter-class>
org.jasig.cas.client.util.HttpServletRequestWrapperFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>CAS HttpServletRequest Wrapper Filter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!--
该过滤器使得开发者可以通过org.jasig.cas.client.util.AssertionHolder来获取用户的登录名。
比如AssertionHolder.getAssertion().getPrincipal().getName()。
-->
<filter>
<filter-name>CAS Assertion Thread Local Filter</filter-name>
<filter-class>org.jasig.cas.client.util.AssertionThreadLocalFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>CAS Assertion Thread Local Filter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- 自动根据单点登录的结果设置本系统的用户信息-->
<filter>
<display-name>AutoSetUserAdapterFilter</display-name>
<filter-name>AutoSetUserAdapterFilter</filter-name>
<filter-class>aurora.plugin.sso.cas.AutoSetUserFilter</filter-class>
<init-param>
<param-name>roleSelectPageUrl</param-name>
<param-value>https://sso.:8080/yourapp/role_select.screen</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>AutoSetUserAdapterFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- ======================== 单点登录结束 ======================== -->
前面几个都是CAS的标准配置,最后一个AutoSetUserAdapterFilter(自定义,可以取其他任意名字)才是我们支持cas的客户化程序。其中roleSelectPageUrl是指用户完成单点登录后跳转的页面。
本文档撰写时java web项目和CAS用同一个tomcat,所以都用的https。否则只需要配置CAS的链接为HTTPS,本项目连接用HTTP。