一、搭建cas server
1.下载war包
2.打开cmd窗口执行以下命令,命令如下(指定ip):
keytool -genkey -v -alias casbm -keyalg RSA -keystore D:\cas\keystore\casbm.keystore -ext SAN=IP:192.168.2.166
3.我们生成秘钥库后需要从秘钥库中导出证书,打开cmd窗口,命令如下:
keytool -export -trustcacerts -alias casbm -file D:/cas/keystore/casbm.cer -keystore D:/cas/keystore/casbm.keystore
4.我们从秘钥库导出证书后需要将证书导入到JDK证书库中,打开cmd窗口,命令如下,其中最后的路径为你本地jdk的路径,要确保该路径正确(此处密码不是自己设置的,是默认密码:changeit):
keytool -import -trustcacerts -alias casbm -file D:/cas/keystore/casbm.cer -keystore “D:/Configure/java/java8/jre/lib/security/cacerts”
5.由于cas需要https协议访问,所以我们要配置tomcat也支持https协议,我们找到我们的tomcat的server.xml文件,加入如下配置:
<Connector port=“8443” protocol=“org.apache.coyote.http11.Http11NioProtocol”
maxThreads=“150” SSLEnabled=“true” scheme=“https” secure=“true”
clientAuth=“false” sslProtocol=“TLS” keystoreFile=“D:\cas\keystore\casbm.keystore” keystorePass=“123456”/>
6.将之前下载的cas包放入tomcat中启动,首先将war包放入tomcat的webapps下,改名为cas,启动tomcat
7.启动完成后我们访问登录页面验证是否启动成功,访问地址如下,用户名为:casuser 密码为:Mellon:
https://localhost:8443/cas
8.用户名密码是在application.properties配置文件中指定的(需要删除原cas.war,避免覆盖)
##
# CAS Authentication Credentials
#
cas.authn.accept.users=dagly::most123456789
#cas.authn.jdbc.query[0].url=jdbc:kingbase8://192.168.2.166:54321/WANGLIAN
#cas.authn.jdbc.query[0].user=WANGLIAN
#cas.authn.jdbc.query[0].password=manager123
#cas.authn.jdbc.query[0].sql=select * from hdrole where login_name = ?
#cas.authn.jdbc.query[0].fieldPassword=password
#cas.authn.jdbc.query[0].driverClass=com.kingbase8.Driver
#cas.authn.jdbc.query[0].passwordEncoder.type=DEFAULT
#cas.authn.jdbc.query[0].passwordEncoder.characterEncoding=GBK
#MD5加密策略
#cas.authn.jdbc.query[0].passwordEncoder.encodingAlgorithm=MD5
#是否开启json识别功能,默认为false
cas.serviceRegistry.initFromJson=true
#忽略https安全协议,使用 HTTP 协议
cas.tgc.secure=false
cas.logout.followServiceRedirects=true
9.使用数据库连接时加入jar:
cas-server-support-jdbc-5.3.1.jar
cas-server-support-jdbc-drivers-5.3.1.jar
cas-server-support-jdbc-authentication-5.3.1.jar
connector-java-5.1.34_1.jar
二、接入CAS 的client
1.修改tomcat的server.xml引入证书:,项目中引入cas-client-core-3.6.4.jar
<Connector connectionTimeout="20000" port="8080" protocol="HTTP/1.1" redirectPort="8443" keystoreFile="D:\cas\keystore\casbm.keystore" keystorePass="123456"/>
2.在web.xml中加入配置(删掉注释,此处为了解释):
//单点登出的listener
<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>
//自定义的顶层filer,用于处理请求
<filter>
<filter-name>FetchCasTicketFilter</filter-name>
<filter-class>com.hidy.auth.servlet.FetchCasTicketFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>FetchCasTicketFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
//认证过滤器,此处重写,用官方的无法配置不过滤的路径
<filter>
<filter-name>CASFilter</filter-name>
<filter-class>com.hidy.auth.servlet.AuthenticationFilter</filter-class>
<init-param>
<param-name>casServerLoginUrl</param-name>
<param-value>https://192.168.2.166:8443/cas/login</param-value>//CAS server登录页
</init-param>
<init-param>
<param-name>serverName</param-name>
<param-value>http://192.168.2.166:8080/</param-value>//项目地址
</init-param>
<init-param>
<param-name>ignorePattern</param-name>
<param-value>/defaultpsy.*|/theme/*|/LoginServlet|/images/*|/TransInterface</param-value>//
</init-param>
</filter>
<filter-mapping>
<filter-name>CASFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<filter>
<filter-name>CAS Validation Filter</filter-name>//认证拦截器
<filter-class>org.jasig.cas.client.validation.Cas20ProxyReceivingTicketValidationFilter</filter-class>
<init-param>
<param-name>targetBeanName</param-name>
<param-value>loginSinglePointScoreBp</param-value>
</init-param>
<init-param>
<param-name>casServerUrlPrefix</param-name>
<param-value>https://192.168.2.166:8443/cas</param-value>
</init-param>
<init-param>
<param-name>serverName</param-name>
<param-value>http://192.168.2.166:8080/</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CAS Validation Filter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
//处理request,能够用request.getRemoteUser()获取当前登录人
<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>
//单点的登录servlet(即对原来的登录servlet复制,逻辑进行修改,原来的用于三员登录)
<servlet>
<servlet-name>LoginServletCas</servlet-name>
<servlet-class>com.hidy.auth.servlet.LoginServletCas</servlet-class>
</servlet>
<servlet-mapping>
<servlet-name>LoginServletCas</servlet-name>
<url-pattern>/LoginServletCas</url-pattern>
</servlet-mapping>
3.FetchCasTicketFilter代码,顶级过滤器
package com.hidy.auth.servlet;
import java.io.IOException;
import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.jasig.cas.client.util.CommonUtils;
import com.hidy.hdoa6.util.StaticData;
import org.jasig.cas.client.util.CommonUtils;
public class FetchCasTicketFilter implements Filter {
@Override
public void destroy() {
// TODO Auto-generated method stub
}
@Override
public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain)
throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest) req;
HttpServletResponse response=(HttpServletResponse) res;
String path = request.getServletPath();
Object id = request.getSession().getAttribute("UserID");
String ticket = request.getParameter("ticket");
String requestUri=request.getScheme()+"://"+request.getServerName()+":"+request.getServerPort()+request.getContextPath()+"/";
//对一些路径不拦截
if(id == null && ticket==null && !(path.endsWith("defaultp.jsp") || path.endsWith(".js") || path.endsWith(".css") || path.endsWith("/LoginServlet")|| path.endsWith("/LoginServletCas")|| path.endsWith("/defaultpsy.jsp")|| path.endsWith(".png")||path.endsWith("/TransInterface"))) {
String result = "<script>top.window.location.href='"+StaticData.HD_CA_URI+"/login?service="+requestUri+"'</script>";
response.getWriter().print(result);
response.getWriter().close();
}else {
//获取cas的ticket,看cas server配置的规则,如果是认证完即失效,则此处可以不写
String queryString = request.getQueryString();
if(queryString != null && queryString.contains("ticket")){
Cookie cookie=new Cookie("ticket",queryString.substring(queryString.indexOf("=") + 1) );
cookie.setMaxAge(Integer.MAX_VALUE);
//将Cookie加到response中
response.addCookie(cookie);
}
chain.doFilter(req, res);
}
}
@Override
public void init(FilterConfig filterConfig) throws ServletException {
}
}
4.AuthenticationFilter代码(不一定一致,当前用的cas client core3.6.4,其他版本反编译后修改逻辑,主要是对不拦截路径的放行)
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.jasig.cas.client.Protocol;
import org.jasig.cas.client.authentication.AuthenticationRedirectStrategy;
import org.jasig.cas.client.authentication.ContainsPatternUrlPatternMatcherStrategy;
import org.jasig.cas.client.authentication.DefaultAuthenticationRedirectStrategy;
import org.jasig.cas.client.authentication.DefaultGatewayResolverImpl;
import org.jasig.cas.client.authentication.EntireRegionRegexUrlPatternMatcherStrategy;
import org.jasig.cas.client.authentication.ExactUrlPatternMatcherStrategy;
import org.jasig.cas.client.authentication.GatewayResolver;
import org.jasig.cas.client.authentication.RegexUrlPatternMatcherStrategy;
import org.jasig.cas.client.authentication.UrlPatternMatcherStrategy;
import org.jasig.cas.client.configuration.ConfigurationKey;
import org.jasig.cas.client.configuration.ConfigurationKeys;
import org.jasig.cas.client.util.AbstractCasFilter;
import org.jasig.cas.client.util.CommonUtils;
import org.jasig.cas.client.util.ReflectUtils;
import org.jasig.cas.client.validation.Assertion;
public class AuthenticationFilter extends AbstractCasFilter {
private String casServerLoginUrl;
private boolean renew;
private boolean gateway;
private String method;
private GatewayResolver gatewayStorage;
private AuthenticationRedirectStrategy authenticationRedirectStrategy;
private UrlPatternMatcherStrategy ignoreUrlPatternMatcherStrategyClass;
private static final Map<String, Class<? extends UrlPatternMatcherStrategy>> PATTERN_MATCHER_TYPES = new HashMap();
private String excludePaths;
public AuthenticationFilter() {
this(Protocol.CAS2);
}
protected AuthenticationFilter(Protocol protocol) {
super(protocol);
this.renew = false;
this.gateway = false;
this.gatewayStorage = new DefaultGatewayResolverImpl();
this.authenticationRedirectStrategy = new DefaultAuthenticationRedirectStrategy();
this.ignoreUrlPatternMatcherStrategyClass = null;
}
protected void initInternal(FilterConfig filterConfig) throws ServletException {
if (!this.isIgnoreInitConfiguration()) {
super.initInternal(filterConfig);
String loginUrl = this.getString(ConfigurationKeys.CAS_SERVER_LOGIN_URL);
if (loginUrl != null) {
this.setCasServerLoginUrl(loginUrl);
} else {
this.setCasServerUrlPrefix(this.getString(ConfigurationKeys.CAS_SERVER_URL_PREFIX));
}
this.setRenew(this.getBoolean(ConfigurationKeys.RENEW));
this.setGateway(this.getBoolean(ConfigurationKeys.GATEWAY));
this.setMethod(this.getString(ConfigurationKeys.METHOD));
String ignorePattern = this.getString(ConfigurationKeys.IGNORE_PATTERN);
String ignoreUrlPatternType = this.getString(ConfigurationKeys.IGNORE_URL_PATTERN_TYPE);
Class gatewayStorageClass;
if (ignorePattern != null) {
gatewayStorageClass = (Class)PATTERN_MATCHER_TYPES.get(ignoreUrlPatternType);
if (gatewayStorageClass != null) {
this.ignoreUrlPatternMatcherStrategyClass = (UrlPatternMatcherStrategy)ReflectUtils.newInstance(gatewayStorageClass.getName(), new Object[0]);
} else {
try {
this.logger.trace("Assuming {} is a qualified class name...", ignoreUrlPatternType);
this.ignoreUrlPatternMatcherStrategyClass = (UrlPatternMatcherStrategy)ReflectUtils.newInstance(ignoreUrlPatternType, new Object[0]);
} catch (IllegalArgumentException var7) {
this.logger.error("Could not instantiate class [{}]", ignoreUrlPatternType, var7);
}
}
if (this.ignoreUrlPatternMatcherStrategyClass != null) {
this.ignoreUrlPatternMatcherStrategyClass.setPattern(ignorePattern);
}
}
gatewayStorageClass = this.getClass(ConfigurationKeys.GATEWAY_STORAGE_CLASS);
if (gatewayStorageClass != null) {
this.setGatewayStorage((GatewayResolver)ReflectUtils.newInstance(gatewayStorageClass, new Object[0]));
}
Class<? extends AuthenticationRedirectStrategy> authenticationRedirectStrategyClass = this.getClass(ConfigurationKeys.AUTHENTICATION_REDIRECT_STRATEGY_CLASS);
if (authenticationRedirectStrategyClass != null) {
this.authenticationRedirectStrategy = (AuthenticationRedirectStrategy)ReflectUtils.newInstance(authenticationRedirectStrategyClass, new Object[0]);
}
excludePaths = this.getString(new ConfigurationKey("ignorePattern", (Object)null));
excludePaths = excludePaths.trim();
}
}
public void init() {
super.init();
String message = String.format("one of %s and %s must not be null.", ConfigurationKeys.CAS_SERVER_LOGIN_URL.getName(), ConfigurationKeys.CAS_SERVER_URL_PREFIX.getName());
CommonUtils.assertNotNull(this.casServerLoginUrl, message);
}
public final void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest request = (HttpServletRequest)servletRequest;
HttpServletResponse response = (HttpServletResponse)servletResponse;
//三员用户直接放行 if(null!=request.getSession().getAttribute("isXtgly")||null!=request.getSession().getAttribute("isAqbmy")||null!=request.getSession().getAttribute("isAqsjy")) {
filterChain.doFilter(request, response);
return;
}
if (this.isRequestUrlExcluded(request)) {
this.logger.debug("Request is ignored.");
filterChain.doFilter(request, response);
return;
} else {
HttpSession session = request.getSession(false);
Assertion assertion = session != null ? (Assertion)session.getAttribute("_const_cas_assertion_") : null;
if (assertion != null) {
filterChain.doFilter(request, response);
} else {
String serviceUrl = this.constructServiceUrl(request, response);
String ticket = this.retrieveTicketFromRequest(request);
boolean wasGatewayed = this.gateway && this.gatewayStorage.hasGatewayedAlready(request, serviceUrl);
if (!CommonUtils.isNotBlank(ticket) && !wasGatewayed) {
this.logger.debug("no ticket and no assertion found");
String modifiedServiceUrl;
if (this.gateway) {
this.logger.debug("setting gateway attribute in session");
modifiedServiceUrl = this.gatewayStorage.storeGatewayInformation(request, serviceUrl);
} else {
modifiedServiceUrl = serviceUrl;
}
this.logger.debug("Constructed service url: {}", modifiedServiceUrl);
String urlToRedirectTo = CommonUtils.constructRedirectUrl(this.casServerLoginUrl, this.getProtocol().getServiceParameterName(), modifiedServiceUrl, this.renew, this.gateway, this.method);
this.logger.debug("redirecting to \"{}\"", urlToRedirectTo);
this.authenticationRedirectStrategy.redirect(request, response, urlToRedirectTo);
} else {
filterChain.doFilter(request, response);
}
}
}
}
public final void setRenew(boolean renew) {
this.renew = renew;
}
public final void setGateway(boolean gateway) {
this.gateway = gateway;
}
public void setMethod(String method) {
this.method = method;
}
public final void setCasServerUrlPrefix(String casServerUrlPrefix) {
this.setCasServerLoginUrl(CommonUtils.addTrailingSlash(casServerUrlPrefix) + "login");
}
public final void setCasServerLoginUrl(String casServerLoginUrl) {
this.casServerLoginUrl = casServerLoginUrl;
}
public final void setGatewayStorage(GatewayResolver gatewayStorage) {
this.gatewayStorage = gatewayStorage;
}
//自行修改代码
private boolean isRequestUrlExcluded(HttpServletRequest request) {
if (this.ignoreUrlPatternMatcherStrategyClass == null) {
return false;
} else {
StringBuffer urlBuffer = request.getRequestURL();
if (request.getQueryString() != null) {
urlBuffer.append("?").append(request.getQueryString());
}
String requestUri = urlBuffer.toString();
return this.ignoreUrlPatternMatcherStrategyClass.matches(requestUri);
}
}
public final void setIgnoreUrlPatternMatcherStrategyClass(UrlPatternMatcherStrategy ignoreUrlPatternMatcherStrategyClass) {
this.ignoreUrlPatternMatcherStrategyClass = ignoreUrlPatternMatcherStrategyClass;
}
static {
PATTERN_MATCHER_TYPES.put("CONTAINS", ContainsPatternUrlPatternMatcherStrategy.class);
PATTERN_MATCHER_TYPES.put("REGEX", RegexUrlPatternMatcherStrategy.class);
PATTERN_MATCHER_TYPES.put("FULL_REGEX", EntireRegionRegexUrlPatternMatcherStrategy.class);
PATTERN_MATCHER_TYPES.put("EXACT", ExactUrlPatternMatcherStrategy.class);
}
}
5.登录页验证是否已经cas登录
String user=request.getRemoteUser();
String casloginflag="false";
if(!"".equals(user)&&null!=user){//已经在cas登录
casloginflag="true";
}
为true是直接跳转到LoginServletCas
6.三员
复制一个登录页,登录servlet,不验证cas,只验证session中三员是否登录,此页面需要在web.xml中修改,放行此页面和相关servlet(包括上面AuthenticationFilter的逻辑处理)
参考资料:
CAS实现单点登录
自定义cas客户端核心过滤器AuthenticationFilter
其他