




版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
1、.白话数字签名 3 Web程序中的数字签名 转帖白话数字签名3-Web程序中的数字签名摘要阅读本文并探究-如何打破Web程序无状态性这个让人抓狂的障碍实现自动显示签名结果和批量签名功能。-如何将签名功能封装到一个实现了I Handler接口的类库中,使Client端的代码尽可能的简单。-使用数字签名API函数需要注意的几个问题。本文介绍在Web程序中使用数字签名所遇到的特殊困难和解决方法,并给出一个超简单但相当实用的DEMO。DEMO程序的效果让我们先来看看实现之后的效果。让Client端代码尽可能的简单我们将数字签名操作的复杂性全部封装到一个命名空间为mylib.util.lnca的类库中,
2、类库只暴露一个名为Signer的类。Signer的Client本例中的Default.aspx的职责只有-构造一个含有待签名的数据的Dictionary作为Signer的输入,然后调用Signer.do_sign函数进展数字签名。-在页面上放置一个专门用于获得并显示签名结果的按钮,并将这个按钮的ClientID传递给Signer,这样Signer在完成签名后就可以自动触发这个按钮。在将程序发布给最终用户时,要把这个按钮的top属性设为-10000,这样最终用户就看不到这个按钮了。Default.aspx的设计视图的截图Default.aspx的源代码如下%Page Language="
3、;C#"AutoEventWireup="true"CodeFile="Default.aspx.cs"Inherits="_Default"%!DOCTYPE html PUBLIC"-/W3C/DTD XHTML 1.0 Transitional/EN""htmlxmlns="headrunat="server"title无标题页/title/head body formid="form1"runat="server"ta
4、ble tr td asp:ButtonID="do_sign_button"runat="server"Text="签名"OnClick="do_sign_button_Click"/asp:LabelID="Label1"runat="server"Text="Label"/asp:Label/td td asp:ButtonID="show_signed_data_button"runat="server"Te
5、xt="显示签名结果自动"OnClick="show_signed_data_button_Click"/td/tr tr tdstyle="border:solid 1px black;vertical-align:top;"asp:GridViewID="sign_candidates_gridview"runat="server"Caption="签名前的数据"CellPadding="4"ForeColor="#333333"F
6、ont-Names="宋体"Font-Size="10pt"FooterStyleBackColor="#1C5E55"Font-Bold="True"ForeColor="White"/RowStyleBackColor="#E3EAEB"/EditRowStyleBackColor="#7C6F57"/SelectedRowStyleBackColor="#C5BBAF"Font-Bold="True"ForeC
7、olor="#333333"/PagerStyleBackColor="#666666"ForeColor="White"HorizontalAlign="Center"/HeaderStyleBackColor="#1C5E55"Font-Bold="True"ForeColor="White"/AlternatingRowStyleBackColor="White"/asp:GridView/td tdstyle="bor
8、der:solid 1px black;vertical-align:top;"asp:GridViewID="signed_data_gridview"runat="server"Caption="签名结果"BackColor="LightGoldenrodYellow"BorderColor="Tan"BorderWidth="1px"CellPadding="2"ForeColor="Black"OnRowDataBou
9、nd="signed_data_gridview_RowDataBound"Font-Names="宋体"Font-Size="10pt"FooterStyleBackColor="Tan"/SelectedRowStyleBackColor="DarkSlateBlue"ForeColor="GhostWhite"/PagerStyleBackColor="PaleGoldenrod"ForeColor="DarkSlateBlue"
10、HorizontalAlign="Center"/HeaderStyleBackColor="Tan"Font-Bold="True"/AlternatingRowStyleBackColor="PaleGoldenrod"/asp:GridView/td/tr/table/form/body/html using System;using System.Data;using System.Configuration;using System.Web;using System.Web.Security;using
11、System.Web.UI;using System.Web.UI.WebControls;using System.Web.UI.WebControls.WebParts;using System.Web.UI.HtmlControls;using System.Collections.Generic;using mylib.util.lnca;public partialclass _Default:System.Web.UI.Pageprotectedvoid Page_Loadobject sender,EventArgs eprotectedvoid do_sign_button_C
12、lickobject sender,EventArgs e/这是待签名的数据,保存在一个Dictionary中。Key为数据的ID,Value为待签名的数据。Dictionary string,string sign_candidates=new Dictionary string,string;sign_candidates.Add"1","123.45";sign_candidates.Add"2","678.90";sign_candidates.Add"3","zhf"
13、;;sign_candidates.Add"4","7788";sign_candidates.Add"5","1-2-3";sign_candidates.Add"6","cnblogs";sign_candidates_gridview.DataSource=sign_candidates;sign_candidates_gridview.DataBind;/调用Signer.do_sign进展签名Signer.do_signPage,show_signed_data_b
14、utton.ClientID,sign_candidates;protectedvoid show_signed_data_button_Clickobject sender,EventArgs eifSigner.error_code=0/签名成功signed_data_gridview.DataSource=Signer.signed_datas;signed_data_gridview.DataBind;else/签名失败Label1.Text=Signer.error_message;protectedvoid signed_data_gridview_RowDataBoundobje
15、ct sender,GridViewRowEventArgs e/每个签名结果的长度都要将近2000个字符,会把GridView撑得很大,为了方便写Blog时截图,我/加了一个滚动条,实际作程序时是不需将签名数据显示给用户看的,也就用不着这段代码了。ife.Row.RowType=DataControlRowType.DataRowstring content=e.Row.Cells1.Text;e.Row.Cells1.Text="div style='overflow:auto;width:300px;height:150px;'"+content+&q
16、uot;/div";由于Signer是一个 处理程序,所以需要在Web.config中添加一行对Signer.ashx的注册:?xml version="1.0"?configuration appSettings/connectionStrings/system.web Handlers addpath="Signer.ashx"verb="*"type="mylib.util.lnca.Signer,mylib.util.lnca"validate="false"/ Handler
17、s/system.web/configuration有关 处理程序的创立和应用,可以看?实战 处理程序 Handler系列?。由于我们把复杂性都放在了Signer.cs中,Signer.cs的代码有些长,我们会在后面讨论它的几个要点。1 using System;2 using System.Collections.Generic;3 using System.Text;4 using System.Web;5 using System.Web.UI;6 using System.Web.SessionState;7 using mylib.util.lnca.Properties;8 usi
18、ng System.Diagnostics;9 10 namespace mylib.util.lnca 1112 publicclass Signer:I Handler,IRequiresSessionState 1314/summary 15/Opens anew window to do signing.16/Example 17/Dictionary string,string sign_candidates=new Dictionary string,string;18/sign_candidates.Add"1","123.45";19/s
19、ign_candidates.Add"2","678.90";20/sign_candidates.Add"3","zhf";21/sign_candidates.Add"4","7788";22/sign_candidates.Add"5","1-2-3";23/sign_candidates.Add"6","cnblogs";24/Signer.do_signPage,on_finished_
20、signing_button.ClientID,sign_candidates;25/summary 26 publicstaticvoid do_signPage page,string on_signing_finished_button_client_id,27 Dictionary string,string sign_candidates2829 Debug.Assertsign_candidates!=null,"sign_candidates should not be null";30 31 Signer.sign_candidates=sign_candi
21、dates;32 Signer.sign_candidates_enumerator=Signer.sign_candidates.GetEnumerator;33 Signer.on_signing_finished_button_client_id=on_signing_finished_button_client_id;34 35/initializes Signer.signed_datas 36 Signer.signed_datas=new Dictionary string,string;37 Signer.signing_counter=0;38 foreachstring k
22、eyin sign_candidates.Keys3940 Signer.signed_datas.Addkey,"";4142 43 error_code=0;44 error_message="";45 46 if!page.ClientScript.IsStartupScriptRegisteredpage.GetType,"OpenSignerWindow"4748 page.ClientScript.RegisterStartupScriptpage.GetType,"OpenSignerWindow",
23、49"window.open'Signer.ashx','Signer_ashx','height=100,alwaysRaised=true,width=200,top=300,left=400,toolbar=no,menubar=no,scrollbars=no,resizable=no,location=no,status=no';",true;505152 53/summary 54/Stores error_code during signing.55/summary 56 publicstaticlong err
24、or_code 5758 getreturnlongSystem.Web. Context.Current.Session"mylib.util.lnca.Signer.error_code";59 setSystem.Web. Context.Current.Session"mylib.util.lnca.Signer.error_code"=value;6061 62/summary 63/Stores error_message during signing.64/summary 65 publicstaticstring error_messag
25、e 6667 getreturn System.Web. Context.Current.Session"mylib.util.lnca.Signer.error_message"asstring;68 setSystem.Web. Context.Current.Session"mylib.util.lnca.Signer.error_message"=value;6970 71/summary 72/Stores datas had be signed.73/summary 74 publicstatic Dictionary string,stri
26、ng signed_datas 7576 getreturn System.Web. Context.Current.Session"mylib.util.lnca.Signer.signed_datas"as Dictionary string,string;77 setSystem.Web. Context.Current.Session"mylib.util.lnca.Signer.signed_datas"=value;7879 80/summary 81/The enumerator of sign_candidates 82/summary
27、83 privatestatic IEnumerator KeyValuePair string,string sign_candidates_enumerator 8485 getreturn System.Web. Context.Current.Session"mylib.util.lnca.Signer.sign_candidates_enumerator"as IEnumerator KeyValuePair string,string;86 setSystem.Web. Context.Current.Session"mylib.util.lnca.S
28、igner.sign_candidates_enumerator"=value;8788 89/summary 90/Datas needs signing.91/summary 92 privatestatic Dictionary string,string sign_candidates 9394 get 9596 return System.Web. Context.Current.Session"mylib.util.lnca.Signer.sign_candidates"as Dictionary string,string;9798 set 9910
29、0 System.Web. Context.Current.Session"mylib.util.lnca.Signer.sign_candidates"=value;101102103 104/Returns the current signing progress.105 privatestaticint signing_counter 106107 getreturnintSystem.Web. Context.Current.Session"mylib.util.lnca.Signer.signing_counter";108 setSystem
30、.Web. Context.Current.Session"mylib.util.lnca.Signer.signing_counter"=value;109110 111/summary 112/Returns javascript code called doSignDatafunction at client.113/param name="sourceData"想要进展签名的数据/param 114/param name="signAlgo"签名算法,推荐使用SignAlgo.RSA_MD5/param 115/param n
31、ame="isAddSignCert"是否在结果中携带证书/param 116/param name="isAddSrcData"是否在结果中携带原文/param 117/param name="innerOid"数据类型,使用InnerOid.EMPUTY即可/param 118/param name="isAddTime"是否添加签名时间/param 119/param name="pin"用户口令,假设设为空字符串,那么每次都会提示用户输入密码;假设在此参数中传入了正确的密码,那么只要求用
32、户输入密码一次./param 120/summary 121 privatestring sign_datastring source_data,string sign_algo,bool is_add_sign_cert,bool is_add_src_data,string inner_oid,long is_add_time,string pin122123 returnstring.Format"doSignData'0','1',2,3,'4',5,'6';",124 source_data,125
33、sign_algo,126 is_add_sign_cert=true?"1":"0",127 is_add_src_data=true?"1":"0",128 inner_oid,129 is_add_time,130 pin;131132 133/summary 134/Alias of sign_datasource_data,SignAlgo.RSA_MD5,is_add_sign_cert,true,InnerOid.EMPUTY,0,string.Empty135/summary 136 private
34、string sign_datastring source_data,bool is_add_sign_cert137138 return sign_datasource_data,SignAlgo.RSA_MD5,is_add_sign_cert,true,InnerOid.EMPUTY,0,string.Empty;139140 141/summary 142/Alias of sign_datasource_data,SignAlgo.RSA_MD5,true,true,InnerOid.EMPUTY,0,string.Empty;143/summary 144 privatestrin
35、g sign_datastring source_data145146 return sign_datasource_data,SignAlgo.RSA_MD5,true,true,InnerOid.EMPUTY,0,string.Empty;147148 149/summary 150/Returns signed data from HiddenFields in form.151/summary 152 privatestring get_signed_data Request request153154 ifget_error_coderequest!=0155156 returnst
36、ring.Empty;157158 159 ifrequest.Form"Signer_SubPage_SignedData_HiddenField"=null160161 returnstring.Empty;162163 164 return request.Form"Signer_SubPage_SignedData_HiddenField".ToString;165166 167/summary 168/Returns error_code from the HiddenField in form.169/summary 170 privatel
37、ong get_error_code Request request171172 ifrequest.Form"Signer_SubPage_ErrorCode_HiddenField"=null173174 return-1;175176 177 try 178179 returnlong.Parserequest.Form"Signer_SubPage_ErrorCode_HiddenField".ToString;180181 catchException182183 return-1;184185186 187/summary 188/Retur
38、ns error_message from the HiddenField in form.189/summary 190 privatestring get_error_message Request request191192 ifget_error_coderequest=-1193194 return"获得签名结果失败。";195196 197 ifrequest.Form"Signer_SubPage_ErrorMessage_HiddenField"=null198199 returnstring.Empty;200201 202 retur
39、n request.Form"Signer_SubPage_ErrorMessage_HiddenField".ToString;203204 205/summary 206/Stores the client_id of button of father page wants to auto trigger.207/summary 208 privatestaticstring on_signing_finished_button_client_id 209210 getreturn System.Web. Context.Current.Session"myl
40、ib.util.lnca.Signer.on_signing_finished_button_client_id"asstring;211 setSystem.Web. Context.Current.Session"mylib.util.lnca.Signer.on_signing_finished_button_client_id"=value;212213 214 publicbool IsReusable 215216 getreturntrue;217218 219 publicvoid ProcessRequestSystem.Web. Context
41、 context220221 context.Response.Clear;222 context.Response.ContentType="text/html";223 context.Response.Write"!DOCTYPE html PUBLIC"-/W3C/DTD XHTML 1.0 Transitional/EN""";224 context.Response.Write"html xmlns=""+Environment.NewLine;225 context.Respons
42、e.Write"title签名中/title";226 context.Response.Write"form name="form1"method="post"id="form1""+Environment.NewLine;227 context.Response.WriteSettings.Default.controls+Environment.NewLine;228 context.Response.WriteSettings.Default.js+Environment.NewLine
43、;229 230 ifsign_candidates_enumerator.Current.Key!=null/not first reach here.231232 ifget_error_codecontext.Request=0/signing success 233234 signed_datassign_candidates_enumerator.Current.Key=get_signed_datacontext.Request;/gathers signed data.235236 else/signing failed.237238/sets error_code and er
44、ror_message 239 error_code=get_error_codecontext.Request;240 error_message=get_error_messagecontext.Request;241/terminates signing 242 context.Response.Write"script type='text/javascript'"+Environment.NewLine;243 context.Response.Write244 string.Format"opener.document.getEleme
45、ntById_x'0'.click;",on_signing_finished_button_client_id;245 context.Response.Write"window.close;";246 context.Response.Write"/script"+Environment.NewLine;247248249 250 ifsign_candidates_enumerator.MoveNext251252 signing_counter+;253 context.Response.Write"span正
46、在签名"+signing_counter.ToString+"/"+sign_candidates.Count.ToString+"/span";254 context.Response.Write"script type='text/javascript'"+Environment.NewLine;255 context.Response.Writesign_datasign_candidates_enumerator.Current.Value+Environment.NewLine;256 contex
47、t.Response.Write"/script"+Environment.NewLine;257258 else 259260 context.Response.Write"script type='text/javascript'"+Environment.NewLine;261 context.Response.Write262 string.Format"opener.document.getElementById_x'0'.click;",on_signing_finished_button_
48、client_id;263 context.Response.Write"window.close;";264 context.Response.Write"/script"+Environment.NewLine;265266 context.Response.Write"/form"+Environment.NewLine;267 context.Response.Write"/html"+Environment.NewLine;268269/class Signer 270/namespace mylib.u
49、til.lnca 271 Signer.cs的第227和228行的"Settings.Default.controls"和"Settings.Default.js"是需要发送给客户端阅读器用于回传签名结果的HiddenFields和执行签名操作的Javascript语句。我把它们放在了类库的配置文件里,它们的代码如下:1 objectid="subpage_Signer_SubPage_LNCAToolkits"classid="clsid:6FBE853D-0DB0-4C62-B7DC-B49E9D447AF9"
50、style="width:0px;2 height:0px;"codebase="3/object 4inputid="Signer_SubPage_ErrorCode_HiddenField"name="Signer_SubPage_ErrorCode_HiddenField"type="hidden"/5 inputid="Signer_SubPage_ErrorMessage_HiddenField"name="Signer_SubPage_ErrorMessage_H
51、iddenField"type="hidden"/6 inputid="Signer_SubPage_SignedData_HiddenField"name="Signer_SubPage_SignedData_HiddenField"type="hidden"/1 script type="text/javascript"2 function doSignDatasourceData,signAlgo,isAddSignCert,isAddSrcData,innerOid,isAdd
52、Time,pin34 var caTool=document.getElementById_x"subpage_Signer_SubPage_LNCAToolkits";5 var ret=caTool.EnumClientCert;6 7ifret=089 var signedData=caTool.SignDataExsourceData,signAlgo,isAddSignCert,isAddSignCert,innerOid,isAddTime,pin;10 11 document.getElementById_x"Signer_SubPage_Error
53、Code_HiddenField".value=caTool.ErrorCode;12 document.getElementById_x"Signer_SubPage_ErrorMessage_HiddenField".value=caTool.ErrorMessage;13 document.getElementById_x"Signer_SubPage_SignedData_HiddenField".value=signedData;1415 else 1617 document.getElementById_x"Signer_
54、SubPage_ErrorCode_HiddenField".value=caTool.ErrorCode;18 document.getElementById_x"Signer_SubPage_ErrorMessage_HiddenField".value=caTool.ErrorMessage;19 document.getElementById_x"Signer_SubPage_SignedData_HiddenField".value='';2021 22 document.forms0.submit;2324/scri
55、pt自动显示签名结果我们想要实现这样的交互效果:用户选定想要进展签名的数据后,只要按一个按钮就会自动弹出一个小窗体显示签名的进度;当签名完毕后,可以自动显示签名结果,就像上面那个DEMO程序所展示的那样。假设我们开发的是WinForm的信息系统,实现这样的效果简直易如反掌。可是在Web程序中,我们却遇到了一点费事。自动显示签名结果的困难正如我们在第2篇所介绍的,为了防复制破解,我们是使用USB Key做数字签名。这个USB Key必须插在客户端的电脑上,我们在Server端无法直接控制它,只能通过在客户端阅读器上执行的javascript代码调用一个由辽宁CA认证中心开发的一个ActiveX控
56、件操作USB Key进展签名,再将签名结果通过HiddenFields Post回Server端-不过这个Server端已经不是以前的Server端了,Web程序的这种无状态性没少让我们吃亏。换句话说,我们没方法像下面这样写伪码:protected void do_sign_button_Clickobject sender,EventArgs e1 Dictionary string,string sign_candidates=prepare_sign_candidates;2 Dictionary string,string signed_datas=excute javascript
57、at client browser to sign data,and return signed datas 3signed_data_gridview.DataSource=signed_datas;4 signed_data_gridview.DataBind;实现自动显示签名结果我们遇到的问题的本质是:准备签名数据伪代码第1行、显示签名结果伪代码第3、4行的操作在Server端进展;而使用USB Key进展签名的操作伪代码第2行必须在Client端的阅读器上执行,并且这两种操作是异步的!所以我们只能将显示签名结果的代码放到另一个函数中,在签名完毕后以某种方法触发它。我们在Demo中所使用
58、的方法是,将显示签名结果的代码放到"显示签名结果自动"按钮的Click事件中,在签名完毕后,使用javascript:opener.document.getElementById_xshow_signed_data_button.ClientID.click;来触发这个按钮的Click事件。考虑题我们使用一个"伪隐藏"的按钮可以简单地实现自动显示签名结果的效果,不过这种作法似乎有点土。你能否使用其它更"高级"的方法来实现同样的效果?实现批量签名我们需要让用户按一次按钮,就可以签名n条数据,可是数字签名API SignDataExsou
59、rcedata,.一次只能签名一条数据。我们需要遍历每条待签名数据,调用SignDataEx进展签名。我们有两种选择:1.在Server端进展遍历,每次传送一条数据给Client端进展签名。2.将n条待签名数据一次全部传给Client端,在Client端使用javascript的for循环遍历待签名数据并进展签名。我们在Demo程序中是使用了第1种方法。基于和"自动显示签名结果"一节所述的同样的困难,我们无法在Signer.cs的ProcessRequest中这样写伪码:public void ProcessRequestSystem.Web. Context contex
60、tforeachstring key in sign_candidates.Keysstring signed_data=excute javascript at client browser to sign data,and return signed data好在已经有大师创造了外部迭代器external iterator,我们可以在第一次迭代之前,先创立一个待签名数据的一个外部迭代器,并把它保存在Session中。每次签名后,Client端PostBack回Server端,在Server端从Session中取出这个外部迭代器,调用sign_candidates_enumerator.Mo
61、veNext,之后继续向Client端发送签名用的javascript语句,直至完成全部遍历,请参见Signer.cs的250268行。下面的时序图表示批量签名3条数据的过程。考虑题我们的DEMO实现了第1种方法,你能否实现第2种方法?这两种实现方法各有什么优缺点?综合起来我们把批量签名与自动显示签名结果的功能都放在Signer.cs中,可以用下面这个经过简化的时序图来表示。附录数字签名API简介我们使用的是辽宁省数字认证中心发放的数字证书。他们还提供了两套数字签名API:一个是ActiveX控件;一个是COM组件。两套API都有完好、丰富的数字签名相关的函数,可以单独使用。假设是WinForm程序,直接使用COM组件即可。不过由于Web程序必须使用ActiveX控件,所以我们在作数字签名的时候使用ActiveX控件,在验证签名的时候使用COM组件。也许您手头的API和我们使用
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 2025至2030年中国彩色透明笔筒市场分析及竞争策略研究报告
- 2025-2030年中国环保杯数据监测研究报告
- 2024至2030年中国熊猫水晶工艺品行业投资前景及策略咨询研究报告
- 2024至2030年中国塑料焊接管件行业投资前景及策略咨询研究报告
- 2024年中国防砸工作鞋数据监测报告
- 2024年中国环保型球铁管卡数据监测报告
- 2024年中国多功能液体膜专用油墨数据监测报告
- 茶果园承包合同协议书模板
- 苗木供应安装合同协议
- 衣服代加工合同协议
- 火灾自动报警系统设计规范完整版2025年
- 2025届广东省燕博园联考(CAT)高三下学期3月模拟测试物理试题(原卷版+解析版)
- 2025年铁路小型养路机械市场分析现状
- 《海参的品种与功效》课件
- SZDBZ 171-2016 物业服务人员管理规范
- 《食品营养与健康》课件
- 初级社工师《社会工作实务》考试(重点)题库300题(含答案解析)
- 2024年天津市高考物理试题含答案解析
- 机器狗:技术成熟性能优越场景刚需放量在即2025
- 心理创伤与精神障碍研究-深度研究
- 课题申报书:大学中学融通视域下拔尖创新人才早期培养评价标准体系构建的实证研究
评论
0/150
提交评论