[原创]IssueVision 学习笔记(一)-----使用SoapHeader传递Web Serivices自定义的身份验证数据

在调用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();

//

1<replacewithwse>   
2**CredentialSoapHeader** header = new CredentialSoapHeader();   
3header.Username = username;   
4header.Password = password;   
5dataService.CredentialSoapHeaderValue = header;   
6//</replacewithwse>

InitWebServiceProxy(dataService);

return dataService;
}

通过以上步骤就可以完成Web Services自定义身份验证了.IssueVision中还有很多相关的操作,因为在这里只是讨论一下SoapHeader的用法,就不在列举了.
鄙人见识就这么多了,欢迎大家讨论,提出新的看法.

CopyRight © YellowWee 2004. All Right Reserved.

Published At
Categories with Web编程
Tagged with
comments powered by Disqus