最近使用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下载。