在調(diào)用web serivices時(shí),往往需要身份驗(yàn)證,使得通過驗(yàn)證的用戶才能調(diào)用你web serivices中的方法.當(dāng)然你可以通過將參數(shù)添加到每個(gè)需要自定義身份驗(yàn)證方案的web services方法中去,這需要花費(fèi)很大的精力.issuevision 中使用了非常常用而且有效便捷的方法-----使用soapheader來實(shí)現(xiàn)自定義身份驗(yàn)證數(shù)據(jù)的傳遞.
 soapheader提供了一種方法,用于將數(shù)據(jù)傳遞到web services方法或從web services方法傳遞數(shù)據(jù),條件是該數(shù)據(jù)不直接與web services 方法的主功能相關(guān). 你不用將參數(shù)添加到每個(gè)需要自定義身份驗(yàn)證方案的web services 方法,而可以將引用從 soapheader 派生的類的 soapheaderattribute 應(yīng)用于每個(gè)web services 方法。從 soapheader 派生的類的實(shí)現(xiàn)處理該自定義身份驗(yàn)證方案. issuevision 就是利用soapheader的這種能力來實(shí)現(xiàn)自定義身份驗(yàn)證數(shù)據(jù)傳遞的.
 我們來看一下如何利用soapheader來傳遞數(shù)據(jù).
 1. 首先需要在服務(wù)中定義一個(gè)從 soapheader 派生的類,表示傳入 soap 標(biāo)頭的數(shù)據(jù).
 issuevision 在中issuevisionweb項(xiàng)目(此項(xiàng)目用于發(fā)布web services)中通過創(chuàng)建credentialsoapheader類來實(shí)現(xiàn)第一步.
credentialsoapheader.cs
using system.web.services.protocols;
namespace issuevision.web
{
 public class credentialsoapheader : soapheader
 {
 private string m_username;
 private string m_password;
 public string username
 {
 get{ return m_username;}
 set{ m_username = value;}
 }
 public string password
 {
 get{ return m_password;}
 set{ m_password = value;}
 }
 }
}
 
 2. 將服務(wù)的公共字段聲明為該類型,使該soapheader在web services的公共合同中公開,并在創(chuàng)建代理時(shí)可由客戶端使用.
 issuevision的web services----issuevisionservices.asmx如此實(shí)現(xiàn).
issuevisionservices.asmx代碼片斷:
public class issuevisionservices : webservice
 {
 ...
 private credentialsoapheader m_credentials;
 // custom soap header to pass credentials
 public credentialsoapheader credentials
 {
 get { return m_credentials; }
 set { m_credentials = value; }
 }
 .......
}
 3. 在web services使用 soapheader 自定義屬性定義一組關(guān)聯(lián)的標(biāo)頭,服務(wù)中的每個(gè) webmethod 都可以使用.(默認(rèn)情況下,標(biāo)頭是必需的,但也可以定義可選標(biāo)頭)
 issuevisionservices.asmx代碼片斷:
 ....
 [webmethod(description="returns the lookup tables for issuevision.")]
 [soapheader("credentials")]
 public ivdataset getlookuptables()
 {
 securityhelper.verifycredentials(this); 
 return new ivdata().getlookuptables();
 }
 securityhelper類的verifycredentials方法用來從web services中的soapheader類來得到自定義身份驗(yàn)證憑據(jù)(如用戶名和密碼).
 securityhelper.cs代碼片斷如下:
// verifies the clients credentials
 public static void verifycredentials(issuevisionservices service) 
 {
 if (service.credentials == null || service.credentials.username == null || service.credentials.password == null ) //如果沒有認(rèn)證信息,返回soapexception,這樣就不能匿名調(diào)用web method了
 {
 eventloghelper.logfailureaudit("a login was attempted with missing credential information.");
 throw new soapexception(string.empty, soapexception.clientfaultcode, "security");
 }
 string password = authenticate(service.credentials);
 }
 // authenticates a user's credentials passed in a custom soap header
 private static string authenticate( credentialsoapheader header) 
 {
 dataset dataset = new dataset();
 string dbpasswordhash;
 try 
 {
 sqlconnection conn = new sqlconnection(common.connectionstring);
 sqlcommand cmd = new sqlcommand("getuser", conn);
 cmd.parameters.add("@username", header.username);
 cmd.commandtype = commandtype.storedprocedure;
 sqldataadapter da = new sqldataadapter(cmd);
 da.fill(dataset);
 } 
 catch (exception ex) 
 {
 eventloghelper.logfailureaudit(string.format("the getuser stored procedure encounted a problem: {0}", ex.tostring()));
 throw new soapexception(string.empty, soapexception.serverfaultcode, "database");
 }
 
 // does the user exist?
 if (dataset.tables[0].rows.count == 0) 
 {
 eventloghelper.logfailureaudit(string.format("the username {0} does not exist.", header.username));
 throw new soapexception(string.empty, soapexception.clientfaultcode, "security");
 } 
 else 
 {
 // we found the user, verify the password hash by compare the salt + passwordhash
 datarow datarow = dataset.tables[0].rows[0];
 dbpasswordhash = (string)datarow["passwordhash"];
 string dbpasswordsalt = (string)datarow["passwordsalt"];
 // create a hash based on the user's salt and the input password
 string passwordhash = hashstring(dbpasswordsalt + header.password);
 // does the computed hash match the database hash?
 if (string.compare(dbpasswordhash, passwordhash) != 0)
 {
 eventloghelper.logfailureaudit(string.format("the password for the username {0} was incorrect.", header.username));
 throw new soapexception(string.empty, soapexception.clientfaultcode, "security");
 }
 }
 
 return dbpasswordhash;
}
 4. 最后客戶端在調(diào)用要求標(biāo)頭的方法之前,需直接在代理類上設(shè)置標(biāo)頭.
 issuevision 的smartclient端的webserviceslayer類來調(diào)用此web services
 webserviceslayer.cs程序片斷如下:
private static issuevisionservices getwebservicereference(string username, string password)
 {
 issuevisionservices dataservice = new issuevisionservices();
 
 //<replacewithwse>
 credentialsoapheader header = new credentialsoapheader();
 header.username = username;
 header.password = password;
 dataservice.credentialsoapheadervalue = header;
 //</replacewithwse>
 
 initwebserviceproxy(dataservice);
 
 return dataservice;
}
 通過以上步驟就可以完成web services自定義身份驗(yàn)證了.issuevision中還有很多相關(guān)的操作,因?yàn)樵谶@里只是討論一下soapheader的用法,就不在列舉了. 
 鄙人見識(shí)就這么多了,歡迎大家討論,提出新的看法.
copyright © yellowwee 2004. all right reserved.
菜鳥學(xué)堂: