一、搭建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文件,加入如下配置:
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.jarcas-server-support-jdbc-drivers-5.3.1.jarcas-server-support-jdbc-authentication-5.3.1.jarconnector-java-5.1.34_1.jar
二、接入CAS 的client
1.修改tomcat的server.xml引入证书:,项目中引入cas-client-core-3.6.4.jar
2.在web.xml中加入配置(删掉注释,此处为了解释):
//单点登出的listener
org.jasig.cas.client.session.SingleSignOutHttpSessionListener //单点登出过滤器CAS Single Sign Out Filter org.jasig.cas.client.session.SingleSignOutFilter CAS Single Sign Out Filter /* //自定义的顶层filer,用于处理请求FetchCasTicketFilter com.hidy.auth.servlet.FetchCasTicketFilter FetchCasTicketFilter /* //认证过滤器,此处重写,用官方的无法配置不过滤的路径CASFilter com.hidy.auth.servlet.AuthenticationFilter casServerLoginUrl https://192.168.2.166:8443/cas/login //CAS server登录页serverName http://192.168.2.166:8080/ //项目地址ignorePattern /defaultpsy.*|/theme/*|/LoginServlet|/images/*|/TransInterface //CASFilter /* CAS Validation Filter //认证拦截器org.jasig.cas.client.validation.Cas20ProxyReceivingTicketValidationFilter targetBeanName loginSinglePointScoreBp casServerUrlPrefix https://192.168.2.166:8443/cas serverName http://192.168.2.166:8080/ CAS Validation Filter /* //处理request,能够用request.getRemoteUser()获取当前登录人CAS HttpServletRequest Wrapper Filter org.jasig.cas.client.util.HttpServletRequestWrapperFilter CAS HttpServletRequest Wrapper Filter /* //单点的登录servlet(即对原来的登录servlet复制,逻辑进行修改,原来的用于三员登录)LoginServletCas com.hidy.auth.servlet.LoginServletCas LoginServletCas /LoginServletCas
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 {@Overridepublic void destroy() {// TODO Auto-generated method stub}@Overridepublic 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 = "";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);}}@Overridepublic 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> 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
其他
上一篇:21. 合并两个有序链表播报文章
下一篇:根据经纬度、半径查询区域内设备