NC整合CAS統一認證+單點登入原理
阿新 • • 發佈:2019-02-10
原理及步驟:
進入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
流程圖:
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; } }