一、搭建cas server

1.下载war包

java SAML认证demo java cas认证_java SAML认证demo


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 其他