原理及步驟:
1、浏覽器中輸入應用位址http://IP:port/inedx.jsp。
進入NC伺服器攔截器1處理:如果URI是/index.jsp且ticket==null,且Assertion==null,則跳轉到CAS認證頁面。
2、CAS登入成功,跳轉回業務系統/index.jsp頁面。
進入NC伺服器攔截器1處理:此時ticket!=null,流轉到攔截器2進行ticket校驗。
3、攔截器2校驗未通過則終止;通過則設定Assertion(包含使用者名等資訊),并跳轉到/index.jsp;jsessionid=XX。注意此時的URI是/index.jsp;jsessionid=XX,而不是/inedx.jsp。
4、攔截器1進行處理,此時ticket==null但Assertion!=null,進行ssokey注冊和跳轉到單點登入位址,CAS單點登入成功。
流程圖:
web.xml配置
<!--統一認證 start-->
<!--用于實作單點退出-->
<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>
<!--該過濾器負責使用者的認證工作,判斷使用者是否登入(必須) start-->
<filter>
<filter-name>CASAuthenticationFilter</filter-name>
<filter-class>nc.bs.cas.login.AuthenticationFilter</filter-class>
<init-param>
<!--注意casServerLoginUrl指伺服器的位址 -->
<param-name>casServerLoginUrl</param-name>
<param-value>http://XX:XX</param-value>
</init-param>
<init-param>
<!-- 當指定renew為true時,在請Cas Server時将帶上參數“renew=true”,預設為false -->
<param-name>renew</param-name>
<param-value>false</param-value>
</init-param>
<init-param>
<!-- 指定gateway為true時,在請求Cas Server時将帶上參數“gateway=true”,預設為false。 -->
<param-name>gateway</param-name>
<param-value>false</param-value>
</init-param>
<init-param>
<!--而serverName指的是應用的位址 -->
<param-name>serverName</param-name>
<param-value>http://XX:XX</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CASAuthenticationFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!--該過濾器負責使用者的認證工作 end-->
<!-- 該過濾器配置負責對Ticket的校驗工作,對于client接收到的ticket進行驗證(必須) start -->
<!--這個過濾器可以從ticket取出CAS的session指派到應用系統-->
<filter>
<filter-name>CASValidationFilter</filter-name>
<filter-class>org.jasig.cas.client.validation.Cas20ProxyReceivingTicketValidationFilter</filter-class>
<init-param>
<!--注意casServerLoginUrl指伺服器的位址 -->
<param-name>casServerUrlPrefix</param-name>
<param-value>http://XX:XX</param-value>
</init-param>
<init-param>
<!--而serverName指的是應用的位址 -->
<param-name>serverName</param-name>
<param-value>http://XX:XX</param-value>
</init-param>
<init-param>
<param-name>useSession</param-name>
<param-value>true</param-value>
</init-param>
<init-param>
<param-name>redirectAfterValidation</param-name>
<param-value>true</param-value>
</init-param>
</filter>
<filter-mapping>
<filter-name>CASValidationFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<!-- 該過濾器配置負責對Ticket的校驗工作 end -->
<!--統一認證 end-->
攔截器1核心代碼:
private boolean isExclude(HttpServletRequest request){
boolean isInWhiteList = true;
String uri=request.getRequestURI();
// /index.jsp
// 1. /index.jsp 跳轉到CAS認證頁面
// 2. /index.jsp 有ticket 認證頁面第一次跳回系統時有ticket,讓校驗器處理
if("/index.jsp".equals(uri)){
isInWhiteList = false;
}
// /index.jsp;jsessionid=82547E908AAE29F76F5D598533818E6D.server
// 3. 校驗器處理通過後重定向到系統,/index.jsp;jsessionid或者/;jsessionid
else if(uri!=null&&(uri.startsWith("/index.jsp;jsessionid")||uri.startsWith("/;jsessionid"))){
isInWhiteList = false;
}
return isInWhiteList;
}
@Override
public final void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
throws IOException, ServletException
{
HttpServletRequest request = (HttpServletRequest)servletRequest;
HttpServletResponse response = (HttpServletResponse)servletResponse;
if(isExclude(request)){
filterChain.doFilter(request, response);
return;
}
String ticket = CommonUtils.safeGetParameter(request, getArtifactParameterName());
// 隻有從認證頁面跳回系統那一次請求有ticket
if(CommonUtils.isNotBlank(ticket))
{
log.error("######check ticket, uri="+request.getRequestURI()+", ticket="+ticket);
filterChain.doFilter(request, response);
return;
}
// 存在session則傳回,否則傳回null
HttpSession session = request.getSession(false);
Assertion assertion = session == null ? null : (Assertion)session.getAttribute(AbstractCasFilter.CONST_CAS_ASSERTION);
if(assertion != null)
{
String user=InvocationInfoProxy.getInstance().getUserCode();
if(isNullStr(user)){
log.error("######register ssoKey, uri="+request.getRequestURI());
String loginName = assertion.getPrincipal().getName();
// 登入NC
String appServer=this.serverName;
if(appServer==null){
appServer=request.getScheme() + "://" + request.getLocalAddr()+":"+request.getLocalPort();
}else if(appServer.endsWith("/")){
appServer=appServer.substring(0, appServer.length()-1);
}
// 1.生成ssoKey
String randomKey = IDMaker.makeID(30);
// 拼接NCURL跳轉URL ssoRegServlet?ssoKey=key&userCode=
String regUrl = appServer + "/service/ssoRegServlet?ssoKey=" + randomKey + "&userCode=" + loginName;
// 2.注冊ssoKey
try {
registerConnect(regUrl);
} catch (Exception e) {
Logger.error("注冊ssoKey時異常", e);
}
// 3.通過ssoKey登入
String newUrl=appServer + "/login.jsp?ssoKey=" + randomKey;
response.sendRedirect(newUrl);
return;
}
filterChain.doFilter(request, response);
return;
}else{
// 控制是否啟用CAS統一認證,系統參數異常時不走CAS
try {
List<SysInitVO>list=(List<SysInitVO>) getDao().retrieveByClause(SysInitVO.class, "initcode ='" + SQLTransferMeaningUtil.tmsql(AuthenticationFilter.PARAM_CAS) + "'and pk_org='" + SQLTransferMeaningUtil.tmsql(IOrgConst.GLOBEORG) + "'");
if(list!=null&&list.size()>0){
UFBoolean cas=new UFBoolean(list.get(0).getValue());
if(cas!=null&&cas.booleanValue()==false){
filterChain.doFilter(request, response);
return;
}
}
} catch (Exception e1) {
Logger.error("擷取系統參數錯誤", e1);
filterChain.doFilter(request, response);
return;
}
log.error("######sendRedirect to cas, uri="+request.getRequestURI());
Logger.debug("no ticket and no assertion found");
String serviceUrl = constructServiceUrl(request, response);
String modifiedServiceUrl;
if(gateway)
{
Logger.debug("setting gateway attribute in session");
modifiedServiceUrl = gatewayStorage.storeGatewayInformation(request, serviceUrl);
} else
{
modifiedServiceUrl = serviceUrl;
}
String urlToRedirectTo = CommonUtils.constructRedirectUrl(casServerLoginUrl, getServiceParameterName(), modifiedServiceUrl, renew, gateway);
// 重定向
response.sendRedirect(urlToRedirectTo);
return;
}
}