WebService的安全机制一个Web应用程序具有的一个重要部分是:能够识别用户和控制对资源的访问。确定请求实体身份的行为称为身份验证。通常,用户必须出示凭据(如名称/密码对)以便进行身份验证。一旦经过验证的标识可用,就必须确定此标识是否可以访问给定的资源。WebService的安全机制主要从两个方面考虑,一个是利用Windows安全机制,另一个就是利用SOAP标头,下面分别进行讨论。一、利用Windows安全机制我们来做一个实验,首先做一个最简单的Web服务程序。WebMethod()PublicFunctionHelloWorld()AsStringHelloWorld=HelloWorldEndFunction完成以后,打开Internet服务管理器。找到这个服务程序的虚拟目录,右键,选择“属性”。找到“目录安全性”选项卡。编辑“匿名访问和验证控制”。取消“匿名访问”和“集成Windows验证”,选择“基本验证”。好了,现在如果再想打开这个程序,就会提示用户名和密码,而这个权力是在服务器上设置的。现在我们来做一个客户程序,这是一个普通的Windows程序。添加Web引用。在输入WebService的地址以后,它就会提示你输入用户名和密码,如果不对,你是没有办法调用这个Web服务的。在输入服务器正确的用户名和密码以后,你就可以使用了。现在做一个Button来调用远程的方法。PublicClassForm1InheritsSystem.Windows.Forms.FormDimaAsNewlocalhost.Service2()PrivateSubForm1_Load(ByValsenderAsSystem.Object,ByValeAsSystem.EventArgs)HandlesMyBase.LoadEndSubPrivateSubButton1_Click(ByValsenderAsSystem.Object,ByValeAsSystem.EventArgs)HandlesButton1.ClickTryMsgBox(a.HelloWorld)CatchMsgBox(请求失败)EndTryEndSubEndClass你会发现,运行以后将提示你“运行失败”,这就是说,调用这个方法的时候,还要发送这个服务器的用户名和密码上去。我们可以采用这个方法来解决:PrivateSubForm1_Load(ByValsenderAsSystem.Object,ByValeAsSystem.EventArgs)HandlesMyBase.Load'a.Credentials获取或设置Web服务客户端身份验证的安全凭据'System.Net.NetworkCredential为基于密码的验证方案提供凭据a.Credentials=NewSystem.Net.NetworkCredential(Administrator,)EndSub好了,现在能正常工作了。C#代码:user107.Service1obj=newuser107.Service1();privatevoidbutton1_Click(objectsender,System.EventArgse){label1.Text=obj.HelloWorld();}privatevoidForm1_Load(objectsender,System.EventArgse){obj.Credentials=newSystem.Net.NetworkCredential(Administrator,user107);}利用这个方式,可以杜绝没有权限的用户调用Web服务。二、使用Soap标头自定义身份验证和授权在Internet上,您可能需要对SQL数据库执行自定义身份验证和授权。在这种情况中,应向服务传递自定义凭据(如用户名和密码),并让服务自己处理身份验证和授权。将额外的信息连同请求一起传递给XMLWeb服务的简便方法是通过SOAP标头。为此,需要在服务中定义一个从SOAPHeader派生的类,然后将服务的公共字段声明为该类型。下面我们通过一个例子来说明这个问题。首先做一个Web服务程序。在这个程序里面,需要注意:服务中的每个WebMethod都可以使用SoapHeader自定义属性定义一组关联的标头。默认情况下,标头是必需的,但也可以定义可选标头。SoapHeader属性指定公共字段的名称或者Client或Server类的属性(本标题中称为Headers属性)。在为输入标头调用方法前,WebService设置Headers属性的值;而当方法为输出标头返回时,WebService检索该值。我们可以先做一个标头类:PublicClassAuthHeaderVB:InheritsSoapHeader它继承于SoapHeader,然后把它声明成一个对象:PublicsHeaderAsAuthHeaderVB然后,所有需要标头控制的方法,都需要在前缀上加上标头声明:WebMethod(),SoapHeader(sHeader)PublicFunctionSecureMethod()AsString下面是具体的程序,当然为了简单,得到客户传过来的用户名和密码以后,我们并不是用数据库处理,而是简单的用一个IF语句处理,但是这种方法,可以扩大成各种情况:ImportsSystem.Web.ServicesImportsSystem.Web.Services.ProtocolsWebService(Namespace:=)_PublicClassService1InheritsSystem.Web.Services.WebServicePublicClassAuthHeaderVB:InheritsSoapHeaderPublicUsernameAsStringPublicPasswordAsStringEndClassPublicsHeaderAsAuthHeaderVBWebMethod(),SoapHeader(sHeader)PublicFunctionSecureMethod()AsStringIf(sHeaderIsNothing)ThenReturn错误:请提供凭据EndIfDimusrAsString=sHeader.UsernameDimpwdAsString=sHeader.PasswordIf(AuthenticateUser(usr,pwd))ThenReturn成功:&usr&,&pwdElseReturn错误:未能通过身份验证EndIfEndFunctionWebMethod(),SoapHeader(sHeader)PublicFunctionHelloWorld()AsStringIf(sHeaderIsNothing)ThenReturn错误:请提供凭据EndIfDimusrAsString=sHeader.UsernameDimpwdAsString=sHeader.PasswordIf(AuthenticateUser(usr,pwd))ThenReturn成功:&你好,我的世界ElseReturn错误:未能通过身份验证EndIfEndFunctionPrivateFunctionAuthenticateUser(ByValusrAsString,ByValpwdAsString)AsBooleanIf(Not(usrIsNothing)AndNot(pwdIsNothing))Then'可在此查询数据库以获取凭据...Ifusr=abcAndpwd=123ThenReturnTrueEndIfEndIfReturnFalseEndFunctionEndClass运行一下,我们可以看到提供方法说明的网站。但是这里已经不提供测试,而是提供了用户名和密码的加入的说明。POST/WebService1/Service1.asmxHTTP/1.1Host:localhostContent-Type:text/xml;charset=utf-8Content-Length:lengthSOAPAction:=1.0encoding=utf-8?soap:Envelopexmlns:xsi=:xsd=:soap=:HeaderAuthHeaderVBxmlns=:Headersoap:BodyHelloWorldxmlns=:Body/soap:Envelope现在我们来做一个客户程序,看看SOAP标头到底有什么样的表现。为了进行测试,我们简单的加三个Button。分别用不同的情况调用Web服务的方法。添加Web引用。代码,第一个事件密码有意给的是错的。PublicClassForm1InheritsSystem.Windows.Forms.FormDimaAsNewlocalhost.Service1()'调用SecureMethodPrivateSubButton1_Click(ByValsenderAsSystem.Object,ByValeAsSystem.EventArgs)HandlesButton1.ClickDimmyHeaderAsNewlocalhost.AuthHeaderVB()myHeader.Username=abcmyHeader.Password=1234a.AuthHeaderVBValue=myHeaderMsgBox(a.SecureMethod())EndSub'调用HelloWorldPrivateSubButton2_Click(ByValsenderAsSystem.Object,ByValeAsSystem.EventArgs)HandlesButton2.ClickDimmyHeaderAsNewlocalhost.AuthHeaderVB()myHeader.Username=abcmyHeader.Password=123a.AuthHeaderVBValue=myHeaderMsgBox(a.HelloWorld)EndSub'直接调用HelloWorldPrivateSubButton3_Click(ByValsenderAsSystem.Object,ByValeAsSystem.EventArgs)HandlesButton3.ClickTryMsgBox(a.HelloWorld)CatcheeAsExceptionMsgBox(ee.Message)EndTryEndSubPrivateSubForm1_Load(ByValsenderAsSystem.Object,ByValeAsSystem.EventArgs)HandlesMyBase.LoadEndSubEndClass下面我们来做个实验首先点:“直接调用HelloWorld”它会提示你“进行调用以前,客户端没有设置SOAP标头”,所以直接调用是不可以的。下面,你点一下“调用SecureMethod”,而程序中有意把提供的密码设成错误的。问题是你再点一下“直接调用HelloWorld”,它也提供了一个密码错误的信息。说明标头的设置对第二个方法也是起作用的。好,现在你点一下“调用H