CA认证——使用吉大正元认证系统为门户把关

最近使用JeeCMS的系统需要用到CA认证,之前很是苦逼了一段时间毕竟是第一次接触类似的东西,没有专业的工程师指导,只给了一个demo和几个文档,当时真的是无从下手。幸好通过两个熬夜,不断的尝试终于成功了,下面就把具体内容分享一下。

关于CA认证是什么东西,我想大多数人都知道的,网上银行使用的key宝或者U盾都属于此列,使用数字证书和密钥加固重要密码的认证流程。也就是说,我手里有个钥匙盘,插入钥匙盘,输入钥匙盘的密码,才能通过该认证,否则拒绝通行。具体原理大家可以去百度百科上去熟悉(http://baike.baidu.com/view/356572.htm),此处不再赘言。

CA认证首先要有认证服务器,服务器可以配置认证关键字(相当于应用ID),产生认证原文,进行密码验证,返回认证结果和证书信息。本文主要说明的是客户端的配置和服务器端的交互过程。

涉及到的文件:前台登陆界面,后台两个servlet。

所采用认证方式登陆,则进行以下流程:

前台代码如下:

<!--CA认证开始-->
<script language="JavaScript" type="text/JavaScript">
   	var xmlHttp = null;
   	//启动函数
   	 $(document).ready(function(){
				//doDataProcess();
				//1.删除cookie
				foreach();
				//alert("ready");
				//2.判断登录类型;
				if(!window.ActiveXObject){
			      alert("请使用IE浏览器(IE6-IE8)!");
			      document.getElementById("face").disabled="disabled";
			     	setInputReadOnly(true);
			    }
				checkLoginType();
			}) 	
			
			//下一个跳转方法checkLoginType
			//检测登陆方式
    function checkLoginType()
			{
				//alert("checkLoginType");
				var loginType  = 2;
				var isCaOrUser = true;
				if(loginType!=null)
				{
					if(loginType=="1")//普通帐户密码登陆方法
					{
						divcontrol(0);
						
					}
					else if(loginType=="2")//ca登陆认证方式
					{
						divcontrol(1);
					}
					else if(loginType=="3")//两种登陆方式兼容
					{
						if(isCaOrUser=="true")
						{
						
							divcontrol(1);
						}
						else
						{
							divcontrol(0);
						}
					}
					else//默认为普通帐户密码登陆方法
					{
						divcontrol(0);
					}
				}
				else //默认为普通帐户密码登陆方法
				{
						divcontrol(0);
				}
			} //下一个跳转方法divcontrol
	//判断是否为ca登陆
	function divcontrol(isca){
		//alert("divcontrol");
	var flag ="";
	if(true==isca){//如果参数不为0
		
	 flag =document.getElementById("face").value ;//取到当前的登陆方式,普通登陆还是认证登陆
	 //alert(flag);
	}else{
		flag=isca
	}
		document.getElementById("realname").value = "";
		document.getElementById("username").value = "";
		document.getElementById("password").value = "";
		if(flag==1)
		{//如果登陆方式是认证登陆
			doDataProcess();//3.服务器后台验证。
			setInputReadOnly(true);
		}
		else
		{	
			setInputReadOnly(false);
		}
	}//下一个跳转方法doDataProcess
	function setInputReadOnly(flag){
		if(flag){
			document.getElementById("realname").readOnly = true;
			document.getElementById("username").readOnly = true;
			document.getElementById("password").readOnly = true;	
		}	else{
			document.getElementById("realname").readOnly = false;
			document.getElementById("username").readOnly = false;
			document.getElementById("password").readOnly = false;
		}
	}
	function doDataProcess(){	
		//alert("doDataProcess");
				getAuth_Content();
				rightCheck();
				//testCheck(); 
	}//下一个跳转方法rightCheck
	 //获得认证原文

            getAuth_Content = function(){
            	 createXMLHttpRequest();
				 				//提交url
								 url="random";
				   	     xmlHttp.open("post",url,false);
				   	     xmlHttp.onreadystatechange=ajaxBack;
				   	     xmlHttp.send();  
            }
           //回调函数
		   	     function   ajaxBack(){
						if(xmlHttp.readyState==4){
		   		         if(xmlHttp.status == 200){
		   		         	//
		   		         	var resTxt =xmlHttp.responseText;
				   		 			 $("#original").val(resTxt);
				   		  
		   		         }else{
					   		      Ext.MessageBox.show({
								title : '提示',
								msg : '无法获取认证原文!',
								width :250,
								buttons:{"ok":"确定"},
								icon : Ext.MessageBox.WARNING 
							 
							});
		   		         }
		   		      }
		   		  }
		   		
   	//主要操作方法
   	function rightCheck(){
   		//获取认证原文
             //如果插入UKEY之后验证失败,直接跳出。
    			var loginResult = 'null';   
	          if("failure"==loginResult){
	            	 Ext.MessageBox.show({
					title : '登录提示',
					msg : '用户不存在,请重试!',
					buttons:{"ok":"确定"},
					icon : Ext.MessageBox.WARNING
				});
				return ;
	            }
	          	
				var Auth_Content =  $("#original").val();//此处为动态代码
				//alert("Auth_Content="+Auth_Content);
				document.getElementById("original_jsp").value = Auth_Content;
				var DSign_Subject = document.getElementById("RootCADN").value;
				
				if(Auth_Content==""){
					Ext.MessageBox.show({
					title : '提示',
					msg : '认证原文不能为空!',
					width :250,
					buttons:{"ok":"确定"},
					icon : Ext.MessageBox.WARNING 
				 
				});
				return;
				}else{
					//控制证书为一个时,不弹出证书选择框
					JITDSignOcx.SetCertChooseType(1);
					JITDSignOcx.SetCert("SC","","","",DSign_Subject,"");
					if(JITDSignOcx.GetErrorCode()!=0){
						//alert("错误码:"+JITDSignOcx.GetErrorCode()+" 错误信息:"+JITDSignOcx.GetErrorMessage(JITDSignOcx.GetErrorCode()));
						Ext.MessageBox.show({
					title : '提示',
					msg : '错误码:'+JITDSignOcx.GetErrorCode()+' 错误信息:'+JITDSignOcx.GetErrorMessage(JITDSignOcx.GetErrorCode()),
					width :250,
					buttons:{"ok":"确定"},
					icon : Ext.MessageBox.WARNING 
				 
				});
						return false;
					}else {
						 var temp_DSign_Result = JITDSignOcx.DetachSignStr("",Auth_Content);
						 if(JITDSignOcx.GetErrorCode()!=0){
								//alert("错误码:"+JITDSignOcx.GetErrorCode()+" 错误信息:"+JITDSignOcx.GetErrorMessage(JITDSignOcx.GetErrorCode()));
								Ext.MessageBox.show({
					title : '提示',
					msg : '错误码:'+JITDSignOcx.GetErrorCode()+' 错误信息:'+JITDSignOcx.GetErrorMessage(JITDSignOcx.GetErrorCode()),
					width :250,
					buttons:{"ok":"确定"},
					icon : Ext.MessageBox.WARNING 
				});
								return false;
						 }
					//如果Get请求,需要放开下面注释部分
						 while(temp_DSign_Result.indexOf('+')!=-1) {
							 temp_DSign_Result=temp_DSign_Result.replace("+","%2B");
						 }
						 document.getElementById("signed_data").value = temp_DSign_Result;
					}
				}
				var url = 'auth?original_jsp='+Auth_Content+'&signed_data='+temp_DSign_Result;

				
				readyFun(url);
    }//下一个跳转方法readyFun
    //创建xmlHttp
			function createXMLHttpRequest(){
			    if(window.ActiveXObject){
			        xmlHttp = new ActiveXObject("Microsoft.XMLHTTP");
			    }else if(window.XMLHttpRequest){
			        xmlHttp = new XMLHttpRequest();
			    }
			}
			var perainfo =  "";
			//通过ajax获取人员信息
			function readyFun(url){
		
				 createXMLHttpRequest();
				 //提交url
		   	     xmlHttp.open("get",url);
		   	     xmlHttp.onreadystatechange=ajexBack;
		   	     xmlHttp.send();
		   	     //回调函数
		   	     function   ajexBack(){
						if(xmlHttp.readyState==4){
		   		         if(xmlHttp.status == 200){
		   		         	//由回调函数返回的信息切割成串
			   		         var resultArr = xmlHttp.responseText.split(",");
			   		         var validateResult = resultArr[0];//验证的结果
				   		     var usercode = resultArr[1];//用户编码
				   		     var realname = resultArr[2];//真实姓名
				   		    

				   		      if(validateResult != null &&validateResult !=""&&validateResult=="success"){
				   		        
				   		     }else{
				   		     	Ext.MessageBox.show({
								title : '提示',
								msg : '用户不存在,请重试',
								width :250,
								buttons:{"ok":"确定"},
								icon : Ext.MessageBox.WARNING 
							 });
				   		     	return ;
				   		     }
				   		     if(usercode != null && usercode != ""){
				   		     	document.getElementById("username").value = usercode;//设置用户编码
				   		     	document.getElementById("username").readOnly = true;//设置为只读
				   		     	
				   		     }else{
				   		     	 Ext.MessageBox.show({//失败的时候
								title : '提示',
								msg : '用户不存在,请重试',
								width :250,
								buttons:{"ok":"确定"},
								icon : Ext.MessageBox.WARNING 
				 
				});
				   		     	return ;
				   		     }
				   		     		document.getElementById("realname").value = realname;
				   		        document.getElementById("password").value = "password";
				   		        document.getElementById("password").readOnly = true;
				   		        document.getElementById("realname").readOnly = true;
				   		   }else{
		   		              Ext.MessageBox.show({
					title : '提示',
					msg : '连接服务器出错!',
					width :250,
					buttons:{"ok":"确定"},
					icon : Ext.MessageBox.WARNING 
				 
				});
		   		         }
		   		      }
		   		  }
			 }
			
</script>
<!--CA认证结束-->
random对应RandomServlet,代码如下:
public class RandomServlet extends HttpServlet {

	private static final long serialVersionUID = 3923090461076418525L;

	private String tempURL = null,propertiesURL = null;
	
	private Properties props = null;
	
	/** 认证地址 */
	private final String KEY_AUTHURL = "authURL";

	/** 应用标识 */
	private final String KEY_APP_ID = "appId";

	/**
	 * @see javax.servlet.GenericServlet#init(javax.servlet.ServletConfig)
	 */
	public void init(ServletConfig cfg) throws ServletException {
		// 初始化程序跳转页面
		tempURL = cfg.getInitParameter("url");
		propertiesURL = cfg.getInitParameter("propertiesURL");
	}

	/*
	 * (non-Javadoc)
	 * 
	 * @see
	 * javax.servlet.http.HttpServlet#doGet(javax.servlet.http.HttpServletRequest
	 * , javax.servlet.http.HttpServletResponse)
	 */
	protected void doGet(HttpServletRequest req, HttpServletResponse resp)
			throws IOException, ServletException {
		HttpServletRequest request = (HttpServletRequest) req;
		HttpServletResponse response = (HttpServletResponse) resp;
		//System.out.println("已进入RandomServlet!!!");
		// 设置页面不缓存
		response.setHeader("Pragma", "No-cache");
		response.setHeader("Cache-Control", "no-cache");
		response.setDateHeader("Expires", 0);
		// 初始化属性文件路径
//		String parentPath = request.getSession().getServletContext()
//				.getRealPath("/WEB-INF");
		// 产生认证原文
		String randNum = generateRandomNum();

		if (randNum == null || randNum.trim().equals("")) {
			System.out.println("证书认证数据不完整!");
			response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
			return;
		}

		/**************************
		 * 第三步 服务端返回认证原文   *
		 **************************/
		// 设置认证原文到session,用于程序向后传递,通讯报文中使用
		//System.out.println("设置认证原文到session开始");
		HttpSession session = request.getSession();
		session.setAttribute("original_data", randNum);
		//System.out.println("设置认证原文到session结束");
		// 设置认证原文到页面,给页面程序提供参数,用于产生认证请求数据包
		request.setAttribute("original", randNum);

		// 设置跳转页面
		//request.getRequestDispatcher(tempURL).forward(request, response);
		response.getWriter().write(randNum);
		return;
	}

	protected void doPost(HttpServletRequest req, HttpServletResponse resp)
			throws IOException, ServletException {
		doGet(req, resp);
	}
	/**
	 * 产生认证原文
	 */
	private String generateRandomNum() {
		/**************************
		 * 第二步 服务端产生认证原文   *
		 **************************/
		String num = "1234567890abcdefghijklmnopqrstopqrstuvwxyz";
		int size = 10;
		char[] charArray = num.toCharArray();
		StringBuffer sb = new StringBuffer();
		for (int i = 0; i < size; i++) {
			sb.append(charArray[((int) (Math.random() * 10000) % charArray.length)]);
		}
		return sb.toString();
	}


	/**
	 * 获取文件中的属性值
	 */
	private String getProperties(String key) {
		return props.get(key) == null ? null : (String) props.get(key);
	}
}

auth对应AuthenServlet,代码如下:

/**
 * Copyright © 1999-2008 JIT Co,Ltd. 
 * All right reserved.
 */
package cn.com.jit.cinas;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import java.util.Properties;

import javax.servlet.ServletConfig;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.HttpStatus;
import org.apache.commons.httpclient.methods.PostMethod;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.io.XMLWriter;

import sun.misc.BASE64Encoder;

public class AuthenServlet extends HttpServlet {
	private static final long serialVersionUID = -1686835672374220173L;

	private String tempURL = null, propertiesURL = null;
	private Properties props = null;

	public void init(ServletConfig cfg) throws ServletException {
		tempURL = cfg.getInitParameter("url");
		propertiesURL = cfg.getInitParameter("propertiesURL");
	}

	protected void doGet(HttpServletRequest req, HttpServletResponse resp)
			throws IOException, ServletException {
		HttpServletRequest request = (HttpServletRequest) req;
		HttpServletResponse response = (HttpServletResponse) resp;
		response.setCharacterEncoding("UTF-8");
		/***************************************************************************
		 * isSuccess 认证是否成功,true成功/false失败;errCode 错误码;errDesc 错误描述 *
		 * ************************************************************************/
        //第四步:客户端认证
		//第五步:服务端验证认证原文
		//第六步:应用服务端认证
		//第七步:网关返回认证响应
		//第八步:服务端处理
		
		/***********************************
		 * 获取应用标识及网关认证地址 *
		 ***********************************/
		
		boolean isSuccess = true;
		String errCode = null, errDesc = null;

		// 初始化属性文件路径
		String parentPath = request.getSession().getServletContext()
				.getRealPath("/WEB-INF");

		// 初始化配置文件属性
		InputStream in = new FileInputStream(parentPath + propertiesURL);
		props = new Properties();
		props.load(in);


		// 可以根据需求使用不同的获取方法
		String appId = this.getProperties(KEY_APP_ID);
		String authURL = this.getProperties(KEY_AUTHURL);

		if (!isNotNull(appId) || !isNotNull(authURL)) {
			isSuccess = false;
			errDesc = "应用标识或网关认证地址不可为空";
			System.out.println("应用标识或网关认证地址不可为空\n");
		}

		String original_data = null, signed_data = null,original_jsp = null , username = null , password = null;
		/**************************
		 * 获取认证数据信息 *
		 **************************/
		if (isSuccess) {
			//System.out.println("应用标识及网关的认证地址读取成功!\n应用标识:" + appId + "\n认证地址:"+ authURL + "\n");
			//System.out.println("最先的原文ORIGINAL_DATA="+(String) request.getSession().getAttribute(KEY_ORIGINAL_DATA));
			//System.out.println("从客户端返回的原文="+(String) request.getParameter(KEY_ORIGINAL_JSP));
			//System.out.println("从客户的返回的认证报文="+(String) request.getParameter(KEY_SIGNED_DATA));
			if (isNotNull((String) request.getSession().getAttribute(KEY_ORIGINAL_DATA))
					&& isNotNull((String) request.getParameter(KEY_SIGNED_DATA))
					&&isNotNull((String) request.getParameter(KEY_ORIGINAL_JSP))) {
				// 获取session中的认证原文
				original_data = (String) request.getSession().getAttribute(KEY_ORIGINAL_DATA);
				// 获取request中的认证原文
				original_jsp = (String) request.getParameter(KEY_ORIGINAL_JSP);
				
				/**************************
				 * 第五步:服务端验证认证原文 *
				 **************************/
				if(!original_data.equalsIgnoreCase(original_jsp)){
					isSuccess = false;
					errDesc = "客户端提供的认证原文与服务端的不一致";
					System.out.println("客户端提供的认证原文与服务端的不一致!\n");
					
				}else{
					// 获取证书认证请求包
					signed_data = (String) request.getParameter(KEY_SIGNED_DATA);

					/* 随机密钥 */
					original_data = new BASE64Encoder().encode(original_jsp
							.getBytes());
					//System.out.println("读取认证原文和认证请求包成功!\n认证原文:" + original_jsp+ "\n认证请求包:" + signed_data + "\n");
				}
				

			} else {
				isSuccess = false;
				errDesc = "证书认证数据不完整";
				System.out.println("证书认证数据不完整!\n");
			}
		}
		

		
		/**************************
		 * 第六步:应用服务端认证 *
		 **************************/
		// 认证处理
		try {
			byte[] messagexml = null;
			if (isSuccess) {


				/*** 1 组装认证请求报文数据 ** 开始 **/
				Document reqDocument = DocumentHelper.createDocument();
				Element root = reqDocument.addElement(MSG_ROOT);
				Element requestHeadElement = root.addElement(MSG_HEAD);
				Element requestBodyElement = root.addElement(MSG_BODY);
				/* 组装报文头信息 */
				requestHeadElement.addElement(MSG_VSERSION).setText(
						MSG_VSERSION_VALUE);
				requestHeadElement.addElement(MSG_SERVICE_TYPE).setText(
						MSG_SERVICE_TYPE_VALUE);

				/* 组装报文体信息 */

				// 组装应用标识信息
				requestBodyElement.addElement(MSG_APPID).setText(appId);

				Element authenElement = requestBodyElement.addElement(MSG_AUTH);

				Element authCredentialElement = authenElement
						.addElement(MSG_AUTHCREDENTIAL);
				
				// 组装证书认证信息
				authCredentialElement.addAttribute(MSG_AUTH_MODE,
						MSG_AUTH_MODE_CERT_VALUE );
				authCredentialElement.addElement(MSG_DETACH).setText(
						signed_data);
				authCredentialElement.addElement(MSG_ORIGINAL).setText(
						original_data);
				
				// 组装口令认证信息
				//username = request.getParameter( "" );//获取认证页面传递过来的用户名/口令
				//password = request.getParameter( "" ); 
				//authCredentialElement.addAttribute(MSG_AUTH_MODE,MSG_AUTH_MODE_PASSWORD_VALUE );
				//authCredentialElement.addElement( MSG_USERNAME ).setText(username);
				//authCredentialElement.addElement( MSG_PASSWORD ).setText(password);

				// 组装属性查询列表信息
				Element attributesElement = requestBodyElement
						.addElement(MSG_ATTRIBUTES);

				attributesElement.addAttribute(MSG_ATTRIBUTE_TYPE,
						MSG_ATTRIBUTE_TYPE_PORTION);

				// TODO 取公共信息
				addAttribute(attributesElement, "X509Certificate.SubjectDN",
						"http://www.jit.com.cn/cinas/ias/ns/saml/saml11/X.509");
				addAttribute(attributesElement, "UMS.UserID",
						"http://www.jit.com.cn/ums/ns/user");

				/*** 1 组装认证请求报文数据 ** 完毕 **/

				StringBuffer reqMessageData = new StringBuffer();
				try {
					/*** 2 将认证请求报文写入输出流 ** 开始 **/
					ByteArrayOutputStream outStream = new ByteArrayOutputStream();
					XMLWriter writer = new XMLWriter(outStream);
					writer.write(reqDocument);
					messagexml = outStream.toByteArray();
					/*** 2 将认证请求报文写入输出流 ** 完毕 **/

					reqMessageData.append("请求内容开始!\n");
					reqMessageData.append(outStream.toString() + "\n");
					reqMessageData.append("请求内容结束!\n");
					//System.out.println(reqMessageData.toString() + "\n");
				} catch (Exception e) {
					isSuccess = false;
					errDesc = "组装请求时出现异常";
					System.out.println("组装请求时出现异常");
				}
			}

			/****************************************************************
			 * 创建与网关的HTTP连接,发送认证请求报文,并接收认证响应报文*
			 ****************************************************************/
			/*** 1 创建与网关的HTTP连接 ** 开始 **/
			System.out.println("/*** 1 创建与网关的HTTP连接 ** 开始 **/");
			int statusCode = 500;
			HttpClient httpClient = null;
			PostMethod postMethod = null;
			if (isSuccess) {
				// HTTPClient对象
				httpClient = new HttpClient();
				postMethod = new PostMethod(authURL);

				// 设置报文传送的编码格式
				postMethod.setRequestHeader("Content-Type",
						"text/xml;charset=UTF-8");
				/*** 2 设置发送认证请求内容 ** 开始 **/
				postMethod.setRequestBody(new ByteArrayInputStream(messagexml));
				/*** 2 设置发送认证请求内容 ** 结束 **/
				// 执行postMethod
				try {
					/*** 3 发送通讯报文与网关通讯 ** 开始 **/
				//	System.out.println("/*** 3 发送通讯报文与网关通讯 ** 开始 **/");
					statusCode = httpClient.executeMethod(postMethod);
				//	System.out.println("/*** 3 发送通讯报文与网关通讯 ** 结束 **/");
					/*** 3 发送通讯报文与网关通讯 ** 结束 **/
				} catch (Exception e) {
					isSuccess = false;
					errCode = String.valueOf(statusCode);
					errDesc = e.getMessage();
					System.out.println("与网关连接出现异常\n");
				}
			}
			/****************************************************************
			 * 	第七步:网关返回认证响应*
			 ****************************************************************/
			//System.out.println("第七步:网关返回认证响应*");
			StringBuffer respMessageData = new StringBuffer();
			String respMessageXml = null;
			if (isSuccess) {
				// 当返回200或500状态时处理业务逻辑
				if (statusCode == HttpStatus.SC_OK
						|| statusCode == HttpStatus.SC_INTERNAL_SERVER_ERROR) {
					// 从头中取出转向的地址
					try {
						/*** 4 接收通讯报文并处理 ** 开始 **/
						System.out.println("/*** 4 接收通讯报文并处理 ** 开始 **/");
						byte[] inputstr = postMethod.getResponseBody();

						ByteArrayInputStream ByteinputStream = new ByteArrayInputStream(
								inputstr);
						ByteArrayOutputStream outStream = new ByteArrayOutputStream();
						int ch = 0;
						try {
							while ((ch = ByteinputStream.read()) != -1) {
								int upperCh = (char) ch;
								outStream.write(upperCh);
							}
						} catch (Exception e) {
							isSuccess = false;
							errDesc = e.getMessage();
						}

						if (isSuccess) {
							System.out.println("// 200 表示返回处理成功");
							// 200 表示返回处理成功
							if (statusCode == HttpStatus.SC_OK) {
								respMessageData.append("响应内容开始!\n");
								respMessageData.append(new String(outStream
										.toByteArray(), "UTF-8")
										+ "\n");
								respMessageData.append("响应内容开始!\n");
								respMessageXml = new String(outStream
										.toByteArray(), "UTF-8");
							} else {
								// 500 表示返回失败,发生异常
								respMessageData.append("响应500内容开始!\n");
								respMessageData.append(new String(outStream
										.toByteArray())
										+ "\n");
								respMessageData.append("响应500内容结束!\n");
								isSuccess = false;
								errCode = String.valueOf(statusCode);
								errDesc = new String(outStream.toByteArray());
							}
							//System.out.println(respMessageData.toString()+ "\n");
						}
						/*** 4 接收通讯报文并处理 ** 结束 **/
					} catch (IOException e) {
						isSuccess = false;
						errCode = String.valueOf(statusCode);
						errDesc = e.getMessage();
						//System.out.println("读取认证响应报文出现异常!");
					}
				}
			}

			/*** 1 创建与网关的HTTP连接 ** 结束 **/

			/**************************
			 *第八步:服务端处理 *
			 **************************/
			Document respDocument = null;
			Element headElement = null;
			Element bodyElement = null;
			if (isSuccess) {
				//把string转换为xml
				respDocument = DocumentHelper.parseText(respMessageXml);

				headElement = respDocument.getRootElement().element(MSG_HEAD);
				bodyElement = respDocument.getRootElement().element(MSG_BODY);

				/*** 1 解析报文头 ** 开始 **/
				if (headElement != null) {
					boolean state = Boolean.valueOf(
							headElement.elementTextTrim(MSG_MESSAGE_STATE))
							.booleanValue();
					if (state) {
						isSuccess = false;
						errCode = headElement.elementTextTrim(MSG_MESSAGE_CODE);
						errDesc = headElement.elementTextTrim(MSG_MESSAGE_DESC);
						//System.out.println("认证业务处理失败!\t" + errDesc + "\n");
					}
				}
			}

			if (isSuccess) {
				//System.out.println("解析报文头成功!\n");
				/* 解析报文体 */
				// 解析认证结果集
				Element authResult = bodyElement.element(MSG_AUTH_RESULT_SET)
						.element(MSG_AUTH_RESULT);

				isSuccess = Boolean.valueOf(
						authResult.attributeValue(MSG_SUCCESS)).booleanValue();
				if (!isSuccess) {
					errCode = authResult
							.elementTextTrim(MSG_AUTH_MESSSAGE_CODE);
					errDesc = authResult
							.elementTextTrim(MSG_AUTH_MESSSAGE_DESC);
					//System.out.println("身份认证失败,失败原因:" + errDesc);
				}
			}
			
			if (isSuccess) {
				//System.out.println("身份认证成功!\n");
				// 解析用户属性列表
				Element attrsElement = bodyElement.element(MSG_ATTRIBUTES);
				if (attrsElement != null) {
					List attributeNodeList = attrsElement
							.elements(MSG_ATTRIBUTE);
					for (int i = 0; i < attributeNodeList.size(); i++) {
						Element userAttrNode = (Element) attributeNodeList
								.get(i);
						String name = userAttrNode.attributeValue(MSG_NAME);
						String value = userAttrNode.getTextTrim();
						request.setAttribute(name, value);
						//System.out.println("属性名:" + name + "\t属性值:" + value
							//	+ "\n");
						//this.password = value;
						this.getUsername(value);
					}
				}
			}

		} catch (Exception e) {
			isSuccess = false;
			errDesc = e.getMessage();
		}

		if (!isSuccess) {
			if (isNotNull(errCode)) {
				request.setAttribute("errCode", errCode);
			}
			if (isNotNull(errDesc)) {
				request.setAttribute("errDesc", errDesc);
			}
			System.out.println("处理数据结束,业务处理失败,失败原因:" + errDesc + "\n");
		}else {
			System.out.println("处理数据结束,一切正常!\n");
		}
		
		
		request.setAttribute("isSuccess", new Boolean(isSuccess).toString());
		//request.getRequestDispatcher(tempURL).forward(request, response);
		if(isSuccess){			
			response.getWriter().write("success,"+this.username+","+this.realname);
		}else{
			response.getWriter().write("failure,"+errCode+","+errDesc);	
		}
	}

	private void getUsername(String value) {
		
		String[] users = value.split(",");
		
		String usercodeTemp= users[0].trim();
		String usernameTemp = users[1].trim();
		
		this.realname = usercodeTemp.substring(usercodeTemp.indexOf('=')+1, usercodeTemp.length());
		this.username = usernameTemp.substring(usernameTemp.indexOf('=')+1, usernameTemp.length());
	}

	protected void doPost(HttpServletRequest req, HttpServletResponse resp)
			throws IOException, ServletException {
		doGet(req, resp);
	}

	/**
	 * 判断是否是空串
	 */
	private boolean isNotNull(String str) {
		if (str == null || str.trim().equals(""))
			return false;
		else
			return true;
	}

	/**
	 * 获取文件中的属性值
	 */
	private String getProperties(String key) {
		return props.get(key) == null ? null : (String) props.get(key);
	}

	/**
	 * 向xml插入结点
	 */
	private void addAttribute(Element attributesElement, String name,
			String namespace) {
		Element attr = attributesElement.addElement(MSG_ATTRIBUTE);
		attr.addAttribute(MSG_NAME, name);
		attr.addAttribute(MSG_NAMESPACE, namespace);
	}

	/******************************* 报文公共部分 ****************************/
	/** 报文根结点 */
	private final String MSG_ROOT = "message";

	/** 报文头结点 */
	private final String MSG_HEAD = "head";

	/** 报文体结点 */
	private final String MSG_BODY = "body";

	/** 服务版本号 */
	private final String MSG_VSERSION = "version";

	/** 服务版本值 */
	private final String MSG_VSERSION_VALUE = "1.0";

	/** 服务类型 */
	private final String MSG_SERVICE_TYPE = "serviceType";

	/** 服务类型值 */
	private final String MSG_SERVICE_TYPE_VALUE = "AuthenService";

	/** 报文体 认证方式 */
	private final String MSG_AUTH_MODE = "authMode";

	/** 报文体 证书认证方式 */
	private final String MSG_AUTH_MODE_CERT_VALUE = "cert";
	
	/** 报文体 口令认证方式 */
	private final String MSG_AUTH_MODE_PASSWORD_VALUE = "password";

	/** 报文体 属性集 */
	private final String MSG_ATTRIBUTES = "attributes";

	/** 报文体 属性 */
	private final String MSG_ATTRIBUTE = "attr";

	/** 报文体 属性名 */
	private final String MSG_NAME = "name";

	/** 报文体 属性空间 */
	private final String MSG_NAMESPACE = "namespace";
	/*********************************************************************/

	/******************************* 请求报文 ****************************/
	/** 报文体 应用ID */
	private final String MSG_APPID = "appId";

	/** 报文体 认证结点 */
	private final String MSG_AUTH = "authen";

	/** 报文体 认证凭据 */
	private final String MSG_AUTHCREDENTIAL = "authCredential";

	/** 报文体 detach认证请求包 */
	private final String MSG_DETACH = "detach";

	/** 报文体 原文 */
	private final String MSG_ORIGINAL = "original";
	
	/** 报文体 用户名 */
	private final String MSG_USERNAME = "username";
	
	/** 报文体 口令 */
	private final String MSG_PASSWORD = "password";

	/** 报文体 属性类型 */
	private final String MSG_ATTRIBUTE_TYPE = "attributeType";

	/** 指定属性 */
	private final String MSG_ATTRIBUTE_TYPE_PORTION = "portion";
	
	
	/*********************************************************************/

	/******************************* 响应报文 ****************************/
	/** 报文体 认证结果集状态 */
	private final String MSG_MESSAGE_STATE = "messageState";

	/** 响应报文消息码 */
	private final String MSG_MESSAGE_CODE = "messageCode";

	/** 响应报文消息描述 */
	private final String MSG_MESSAGE_DESC = "messageDesc";

	/** 报文体 认证结果集 */
	private final String MSG_AUTH_RESULT_SET = "authResultSet";

	/** 报文体 认证结果 */
	private final String MSG_AUTH_RESULT = "authResult";

	/** 报文体 认证结果状态 */
	private final String MSG_SUCCESS = "success";

	/** 报文体 认证错误码 */
	private final String MSG_AUTH_MESSSAGE_CODE = "authMessageCode";

	/** 报文体 认证错误描述 */
	private final String MSG_AUTH_MESSSAGE_DESC = "authMessageDesc";
	/*********************************************************************/
	
	/**应用数据库用户名**/
	private String username;
	/**应用数据库真实姓名**/
	private String realname;
	/**应用数据库密码**/
	private String password;
	/**************************** 业务处理常量 ****************************/
	/** 认证地址 */
	private final String KEY_AUTHURL = "authURL";

	/** 应用标识 */
	private final String KEY_APP_ID = "appId";

	/** session中原文 */
	private final String KEY_ORIGINAL_DATA = "original_data";
	
	/** 客户端返回的认证原文,request中原文 */
	private final String KEY_ORIGINAL_JSP = "original_jsp";

	/** 证书认证请求包 */
	private final String KEY_SIGNED_DATA = "signed_data";
	/*********************************************************************/
}

代码显得有些繁琐冗余,不花费一定量的时间是无法真正掌握的,这是吉大正元给的demo,没有经过大的改动直接拿来用了。需要注意以下几点:

1,需要在服务器上配置和应用相关的ID,用于识别不同的应用。

2,需要安装吉大正元自带的驱动程序,否则无法识别key盘,还要使用object标签加载一个动态链接库,如上:

<object classid="clsid:707C7D52-85A8-4584-8954-573EFCE77488"
    id="JITDSignOcx" width="0" codebase="/${res}/jit/JITDSign.cab#version=2,0,24,18"></object>

为了加载一个类,JITDSign可以直接使用类里面的方法。

3,在进行ajax提交的时候注意保持同步,否则可能出现不按顺序执行的情况。

关于文档和demo可以到http://115.com/file/c2gqtrxh下载。

  • 1
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 20
    评论
一款高性能的报表开发工具,特别适用于管理信息系统,如ERP、进销存、财务等软件的报表开发。适用范围广:VB.NET、C#.NET、VB、VC、Delphi、C++Builder、中文编程易语言等一切支持 COM 的开发工具。 功能强大:实现普通格式报表、表格报表、多层表头、票据套打、交叉表等各种报表非常简便;报表完全可编程定义,非常适合开发通用软件中的动态报表。 独有的报表查询显示功能:除了提供报表的打印、打印预览、数据导出等功能,还提供独有的报表查询显示功能,既提供报表查询与输出的集成一次性实现,又能保证数据的一致性与完整性。 报表完全可编程定义,报表运行编程可控制,开发动态报表方便灵活。 特有的分组单元格合并功能,轻松实现常见的中国式报表分组在列中展现形式。 实现票据套打非常简便:对票据套打进行了专门的实现。 提供图表功能,包括饼图、柱状图、叠加柱状图、连线图、散列点图等,在报表中直接实现图表功能。 报表数据导出格式丰富,包括:Excel、PDF、图像、HTML、文本,CSV等多种格式。 支持所有常规条形码。 报表模板提供脚本编程功能,直接在报表模板中自定义报表行为。 支持参数化报表查询SQL语句,轻松实现动态过滤条件筛选报表数据。 运行时打印生成对纸张有适应能力,即使不以设计时纸张进行打印也可以得到输出布局合理的报表。 报表查询显示时提供报表内容文字查找功能。 全中文界面,针对中国报表进行了很多专门实现,如:报表表格线、财务金额线、数字大写金额、负数红字显示、多层表头等。 组件提供丰富交互事件,轻松实现报表穿透(透视)查询和报表交互。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 20
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值