欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

NC集成CAS统一认证+单点登录原理

程序员文章站 2022-05-05 16:32:25
...

原理及步骤:

1、浏览器中输入应用地址http://IP:port/inedx.jsp

进入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==nullAssertion!=null,进行ssokey注册和跳转到单点登录地址,CAS单点登录成功。

流程图:

NC集成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;
        }
    }