1. 程式人生 > >NC整合CAS統一認證+單點登入原理

NC整合CAS統一認證+單點登入原理

原理及步驟:

進入NC伺服器攔截器1處理:如果URI/index.jspticket==null,且Assertion==null,則跳轉到CAS認證頁面。

2CAS登入成功,跳轉回業務系統/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;
        }
    }