
什么是电子签章
电子签章是电子签名的一种表现形式,利用图像处理技术将电子签名操作转化为与纸质文件盖章操作相同的可视效果,同时利用电子签名技术保障电子信息的真实性和完整性以及签名人的不可否认性。
电子合同是企业用途最广的一种合同形式,受《合同法》认可。但由于电子合同以数据电文为载体,涉及到一系列的技术标准,其中最核心、也最重要的是电子签名技术。根据国家法律规定,只有使用可靠电子签名签订的电子合同才具有法律效力。
明道云也十分重视电子签章的功能集成方案。技术顾问经过一段时间的产品调研、测试,以及为客户对接实践,终于形成了较为成熟的电子签章集成对接方案。那么今天,明道云的技术顾问就在这里介绍明道云与法大大的集成对接流程,并简单评价法大大集成的优缺点。
对接流程
1.申请密钥
- 官网联系客服
- 操作开通申请
- 在指定邮箱里收到密钥信息及API对接文档
2.注册账号、证书申请、印章上传

接口名称解释
- 为用户注册法⼤大账号:account_register.api
- 根据账号类型调用对应的接口
- miget_person_verify_url.api 个⼈实名认证⻚面接
- get_company_verify_url.api 企业实名认证⻚⾯接⼝
- 申请实名证书:apply_cert.api
代码块示例
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 |
1.账号注册参数加密 var account_type = input.account_type=='个人'?'1':'2'; var v = input.v; var app_secret = input.app_secret; var app_id = input.app_id; var crypto = require('crypto'); function pad2(n) { return n < 10 ? '0' + n : n } function generateTimeReqestNumber() { var datee = new Date(); var localTime = datee .getTime(); var localOffset=datee .getTimezoneOffset()*60000; //获得当地时间偏移的毫秒数 var utc = localTime + localOffset; //utc即GMT时间 var offset =8; //以北京时间为例,东8区 var hawaii = utc + (3600000*offset); var date = new Date(hawaii); date.setHours(date.getHours()); return date.getFullYear().toString() + pad2(date.getMonth() + 1) + pad2(date.getDate()) + pad2(date.getHours()) + pad2(date.getMinutes()) + pad2(date.getSeconds()); } function sha1(s) { var hash = crypto.createHash('sha1'); hash.update(s); return hash.digest('hex').toUpperCase(); } function md5(s) { var hash = crypto.createHash('md5'); hash.update(s); return hash.digest('hex').toUpperCase(); } function base64(s) { var b = new Buffer.from(s); return b.toString('base64'); } function ast(s) { return s.split('').sort().join(''); } var timestamp = generateTimeReqestNumber(); var msg_digest = base64( sha1( app_id + md5(timestamp) + sha1(app_secret + account_type + input.openid))); return {ts: timestamp, sign: msg_digest, appid: app_id, v: v, openid: input.open_id, accounttype: account_type}; 1.2 调用注册方法 var url=input.url+'/api/account_register.api'; const fetch = require('node-fetch'); const FormData= require('form-data'); var result={}; let data= new FormData(); data.append("app_id",input.appid) data.append("v",input.v) data.append("timestamp",input.ts) data.append("msg_digest",input.sign) data.append("open_id",input.openid) data.append("account_type",input.accounttype) async function getAll(data){ const res = await fetch(url,{ method:"post", body:data }).then(function(response){ if(response.ok){ return response.json(); }else{ return {"error":"无数据"}; } }).catch(function(err){ return {"error":"Fetch错误:"+err}; }); const result = await res; return result; } result=await getAll(data); output={result:result} 2申请实名认证参数加密 var v = input.v; var app_secret = input.appsecret; var aid = input.aid; var crypto = require('crypto'); var data={"customer_id":input.customerid, "verified_way":3, "page_modify":1, "option":"add", "lang":"zh", "organization_type":0, "notify_url":"换为你的接受地址"} function pad2(n) { return n < 10 ? '0' + n : n } function generateTimeReqestNumber() { var datee = new Date(); var localTime = datee .getTime(); var localOffset=datee .getTimezoneOffset()*60000; //获得当地时间偏移的毫秒数 var utc = localTime + localOffset; //utc即GMT时间 var offset =8; //以北京时间为例,东8区 var hawaii = utc + (3600000*offset); var date = new Date(hawaii); date.setHours(date.getHours()); return date.getFullYear().toString() + pad2(date.getMonth() + 1) + pad2(date.getDate()) + pad2(date.getHours()) + pad2(date.getMinutes()) + pad2(date.getSeconds()); } function sha1(s) { var hash = crypto.createHash('sha1'); hash.update(s); return hash.digest('hex').toUpperCase(); } function md5(s) { var hash = crypto.createHash('md5'); hash.update(s); return hash.digest('hex').toUpperCase(); } function base64(s) { var b = new Buffer.from(s); return b.toString('base64'); } function ast(s) { return s.split('').sort().join(''); } var newData = {},params=''; Object.keys(data).sort().map(key => { newData[key]=data[key] params=params+=data[key]; }) var timestamp = generateTimeReqestNumber(); var msg_digest = base64( sha1(aid + md5(timestamp) + sha1(app_secret+params))); newData["app_id"]=aid ; newData["m_verified_way"]=4; newData.timestamp=timestamp; newData.v=v; newData["msg_digest"]=msg_digest; output={ts:timestamp,sign:msg_digest,'app_id':aid, v: v, params:params,newData:JSON.stringify(newData )}; 2.2调用实名认证接口难道链接 var indata=JSON.parse(input.data); var url=input.url+'/api/get_company_verify_url.api'; const fetch = require('node-fetch'); const FormData= require('form-data'); var result={}; let data= new FormData(); Object.keys(indata).forEach((key) => { data.append(key,indata[key]); }) async function getAll(data){ const res = await fetch(url,{ method:"post", body:data }).then(function(response){ if(response.ok){ return response.json(); }else{ return {"error":"无数据"}; } }).catch(function(err){ return {"error":"Fetch错误:"+err}; }); const result = await res; return result; } result=await getAll(data); output={result:re |
拿到接口返回的链接,使用打开界面节点来打开新连接。认证成功后,在你的信息接受地址中调用申请证书接口。
3.配置“上传合同及单个签署”的流程

接口名称解释
- uploaddocs.api 合同上传接⼝
- extsign_auto.api 自动签接⼝
代码块示例
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 |
1.合同上传参数加密 var crypto = require('crypto'); var doc_title='', doc_type=''; var v = input.v; var app_secret = input.appsecret; var aid = input.aid; var contractid=input.contractid+'-'+parseInt(input.ind).toString(); var imgurl=input.imgurl var types=['.doc','.docx','.pdf','.jpg','.jpeg','.png','.bmp'] //法大大不支持图片签章,e签宝支持.这里是为了后面方法公共 function getfiletype(f){ var obj={'ftype':'','fname':''}; for(var i=0;i<types.length;i++){ var find=f.indexOf(types[i]) var temp=f; if(find>-1){ obj.ftype=types[i]; temp=temp.substring(0,find); obj.fname=getfilename(find,temp); break; } } return obj; } function getfilename(find,f){ var fname='' f=f.substring(0,find); var nind=f.lastIndexOf('/'); if(nind>-1){ fname=f.substring(nind+1,f.length); }else{ nind=f.lastIndexOf('='); if(nind>-1){ fname=f.substring(nind+1,f.length); } } return fname; } var obj=getfiletype(imgurl); doc_type=obj.ftype; doc_title=obj.fname; var data={ "contract_id":contractid, "doc_title":doc_title, "doc_type":doc_type, 'doc_url':imgurl} function pad2(n) { return n < 10 ? '0' + n : n } function generateTimeReqestNumber() { var datee = new Date(); var localTime = datee .getTime(); var localOffset=datee .getTimezoneOffset()*60000; //获得当地时间偏移的毫秒数 var utc = localTime + localOffset; //utc即GMT时间 var offset =8; //以北京时间为例,东8区 var hawaii = utc + (3600000*offset); var date = new Date(hawaii); date.setHours(date.getHours()); return date.getFullYear().toString() + pad2(date.getMonth() + 1) + pad2(date.getDate()) + pad2(date.getHours()) + pad2(date.getMinutes()) + pad2(date.getSeconds()); } function sha1(s) { var hash = crypto.createHash('sha1'); hash.update(s); return hash.digest('hex').toUpperCase(); } function md5(s) { var hash = crypto.createHash('md5'); hash.update(s); return hash.digest('hex').toUpperCase(); } function base64(s) { var b = new Buffer.from(s); return b.toString('base64'); } function ast(s) { return s.split('').sort().join(''); } var newData = {},params=''; Object.keys(data).sort().map(key => { newData[key]=data[key] params=params+=data[key]; }) var timestamp = generateTimeReqestNumber(); var msg_digest = base64( sha1(aid + md5(timestamp) + sha1(app_secret+data.contract_id))); newData["app_id"]=aid ; newData.timestamp=timestamp; newData.v=v; newData["msg_digest"]=msg_digest; output={ts:timestamp,sign:msg_digest,'app_id':aid, v: v, params:params,newData:JSON.stringify(newData),contractid:contractid,doc_title:doc_title}; 1.1 合同上传 const fetch = require('node-fetch'); const FormData= require('form-data'); var indata=JSON.parse(input.data); var url=input.url+'/api/uploaddocs.api'; var result={}; var tempparams=''; let data= new FormData(); Object.keys(indata).forEach((key) => { data.append(key,indata[key]); }) async function getAll(data){ const res = await fetch(url,{ method:"post", body:data }).then(function(response){ if(response.ok){ return response.json(); }else{ return {"error":"无数据"}; } }).catch(function(err){ return {"error":"Fetch错误:"+err}; }); const result = await res; return result; } result=await getAll(data); output={result:res |
剩下的接口调用方法几乎一样,请查看 API 接口来调用。
特别注意几点:
- 每个接口的签名规则都需要细看。
- 最后自动签署的流程,需要设置异步通知的地址,因为存在“签署中”的状态。
- 根据异步通知中的接受到的数据,在工作流设置签署后的文件。

结语
务实的明道云,在技术领域不断取得创新突破。每次更新迭代、集成方案,都带给您最美的期待。下一篇文章里,我们将介绍明道云和e签宝的对接案例和流程方法,敬请关注!


