在调用Web Serivices时,往往需要身份验证,使得通过验证的用户才能调用你Web Serivices中的方法.当然你可以通过将参数添加到每个需要自定义身份验证方案的Web services方法中去,这需要花费很大的精力.IssueVision 中使用了非常常用而且有效便捷的方法-----使用SoapHeader来实现自定义身份验证数据的传递. SoapHeader提供了一种方法,用于将数据传递到Web services方法或从Web services方法传递数据,条件是该数据不直接与Web services 方法的主功能相关. 你不用将参数添加到每个需要自定义身份验证方案的Web services 方法,而可以将引用从 SoapHeader 派生的类的 SoapHeaderAttribute 应用于每个Web services 方法。从 SoapHeader 派生的类的实现处理该自定义身份验证方案. IssueVision 就是利用SoapHeader的这种能力来实现自定义身份验证数据传递的.
我们来看一下如何利用SoapHeader来传递数据.
1. 首先需要在服务中定义一个从 SOAPHeader 派生的类,表示传入 SOAP 标头的数据. IssueVision 在中IssueVisionWeb项目(此项目用于发布Web Services)中通过创建CredentialSoapHeader类来实现第一步.
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. 将服务的公共字段声明为该类型,使该SoapHeader在Web Services的公共合同中公开,并在创建代理时可由客户端使用.
IssueVision的Web Services----IssueVisionServices.asmx如此实现.
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 自定义属性定义一组关联的标头,服务中的每个 WebMethod 都可以使用.(默认情况下,标头是必需的,但也可以定义可选标头)
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类来得到自定义身份验证凭据(如用户名和密码).
SecurityHelper.cs代码片断如下:
// verifies the clients credentials public static void VerifyCredentials(IssueVisionServices service) { if (service.Credentials == null || service.Credentials.Username == null || service.Credentials.Password == null ) //如果没有认证信息,返回SoapException,这样就不能匿名调用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. 最后客户端在调用要求标头的方法之前,需直接在代理类上设置标头.
IssueVision 的SmartClient端的WebServicesLayer类来调用此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自定义身份验证了.IssueVision中还有很多相关的操作,因为在这里只是讨论一下SoapHeader的用法,就不在列举了. 鄙人见识就这么多了,欢迎大家讨论,提出新的看法.
CopyRight © YellowWee 2004. All Right Reserved.

|