.NET与Axis的SOAPHeader

来源:互联网 发布:mimics软件 编辑:程序博客网 时间:2024/06/10 09:08
 这两天做WSScore工程项目遇到一个关于Web Service身份认证的问题。当然,简单点做就是向SOAP添加SOAPHeader信息,在SOAP头里面放入身份认证信息。我这个WSScore是用.NET写的Web服务,然后通过从调用端传来的SOAP消息中加入相应的身份认证头信息,就可以让服务端轻松解析了。

虽然对于.NET的调用端可以方便的使用服务实例添加SOAPHeader对象实例到其中,但是,对于我的一个子系统——Axis调用端来说,就不会是这么简单的想添加个头信息,对方(.NET服务端)就能从[SOAPHeader("Credentials")]这种SOAPHeader属性中轻松解析出来的问题。

尽管在Axis调用端写入了头信息,但.NET服务端并没有将这个SOAP头传给SOAPHeader所指定的属性,这一点通过调试,跟踪一下就清楚地看到了,属性为null。究竟为什么,我目前找到相关资料能解释这点。但个人觉得,问题出在[SOAPHeader("xxxHeader")]这个属性赋值究竟是怎样的运行机制。

目前我想出个解决方案,下面就简单说说怎样让.NET读出Axis写的SOAPHeader的身份验证信息。

在.NET下,建立具有SOAPHeader的WebService

public class CredentialSoapHeader : SoapHeader
{
    
public string Username;
    
public string Password;
}


public class Service : System.Web.Services.WebService
{
    
public Service () {}

    
public CredentialSoapHeader Credentials; // 保存SOAP中验证身份的SOAPHeader
    public SoapUnknownHeader[] unknownHeaders; // 保存Axis不能被.NET识别的SOAPHeader

    [WebMethod]
    [SoapHeader(
"Credentials")]    // 对于.NET的调用端可以轻松获取SOAPHeader信息给Credential属性
    [SoapHeader("unknownHeaders")] // 对于Axis的SOAPHeader,就将SOAPHeader赋给unknownHeaders属性
    public string HelloWorld() {
        
this.VerifyCredential(this,flag); // 验证服务
        return "Hello World";
    }


    
private void VerifyCredential(Service s, int right) // 验证服务
    {
        
if (s.Credentials == null && s.unknownHeaders != null// 对于Axis的SOAPHeader,执行
        {
            
foreach (SoapUnknownHeader header in s.unknownHeaders)
            
{
                
string str = header.Element.Name.ToString();
                
if (str.Equals("CredentialSoapHeader")) // 在Axis中仍要保持SOAPHeader的标签正确
                {
                    
// 获取用户名和密码,获取方式同读取XMLNode一样,方式随意
                    string username = header.Element.LastChild.PreviousSibling.InnerText.ToString();
                    
string password = header.Element.LastChild.InnerText.ToString();
                    
if (!Authenticate(username, password,right)) // 如果认证失败则抛异常
                        throw new SoapException("验证失败", SoapException.ClientFaultCode, "Security");
                }

            }

        }

        
else // 对于.NET的调用端,执行这里
        {
            
if (s.Credentials == null || s.Credentials.Username == null || s.Credentials.Password == null)
            
{
                
throw new SoapException("验证失败1", SoapException.ClientFaultCode, "Security");
            }

            
if (!Authenticate(s.Credentials.Username, s.Credentials.Password, right))
                
throw new SoapException("验证失败2", SoapException.ClientFaultCode, "Security");
        }

    }

}

这里简单写一下.net调用端的SOAPHeader添加方式,以作为和Axis的比照。下面是C#编写的应用程序客户端,它可以调用Web服务。先在项目里引用服务。


        WebReference.Service serivce 
= GetWebServiceReference("调用者""密码");
        
private static Service GetWebServiceReference(string username, string password)
        
{
            Service dataService 
= new Service();
            CredentialSoapHeader header 
= new CredentialSoapHeader();
            header.Username 
= username;
            header.Password 
= password;
            dataService.CredentialSoapHeaderValue 
= header;
            dataService.Credentials 
= (System.Net.NetworkCredential)CredentialCache.DefaultCredentials;
            
return dataService;
        }

通过这种方式,就完成了设定SOAPHeader,相对简便些。之后,就可以在应用程序里调用这个service的一些方法了。

下面,我们来看Axis的SOAPHeader怎样添加身份认证信息,使得能让前面的.NET Web服务可以访问SOAP头。拿个登陆的函数作为例子:

    
public int isLoginSuccessful(String studentID, String password){
        
try {
            String endpoint
= ".......";
            Service service 
= new Service();
            Call call 
= (Call)service.createCall();
            call.setTargetEndpointAddress(
new java.net.URL(endpoint));
            call.setOperationName(
new QName("http://www.wsscore.com/Login/SU","Login"));
            call.addParameter(
"studentID",org.apache.axis.encoding.XMLType.XSD_DATE,javax.xml.rpc.ParameterMode.IN);
            call.addParameter(
"password",org.apache.axis.encoding.XMLType.XSD_DATE,javax.xml.rpc.ParameterMode.IN);
            call.setReturnType(org.apache.axis.encoding.XMLType.XSD_INT);
            call.setUseSOAPAction(
true);
            call.setSOAPActionURI(
"http://www.wsscore.com/Login/Rpc");
            
/*========================添加SOAPHeader方式==============================*/
            String namespace 
= "http://www.wsscore.com/";
            
// 注意这里保持SOAP的标签一致CredentialSoapHeader,最好一致~不然就意义不大了~~
            SOAPHeaderElement header = new SOAPHeaderElement(namespace,"CredentialSoapHeader");
            header.setPrefix(
"");
            javax.xml.soap.SOAPElement soapElement 
= header.addChildElement("Username");
            soapElement.addTextNode(
"调用者");
            soapElement 
= header.addChildElement("Password");
            soapElement.addTextNode(
"密码");
            call.addHeader(header);
            
/*========================================================================*/
            
int k = (Integer)call.invoke(new Object[]{studentID,password});
            System.out.println( 
"result is " + k + ".");
            
return k;
        }

        
catch (Exception e) {System.err.println(e.toString());}
        
return -1;
    }

这样,就可以轻松的实现不论是从.NET的调用端,还是从Java的调用端,都可以提供具有身份验证的SOAPHeader了。

小结一下。.NET将Web服务的构建步骤简化对开发人员来说还是比较好的,不过就是简化太多的话,开发人员也都忘了问自己问什么这么做了。Axis是Aapache的开源Web Service架构,能让用户实现比较好用的Java平台上的Web服务。然而,目前的问题似乎仍是平台间的互通信并不如意,只是因为各自的实现方式不同,做同一件事情时,就存在交流障碍。当然,希望能早日看到SOA和Web Services的新成就,尤其这方便比较感兴趣的芸芸众生们~~为了迎接这一辉煌时刻的到来,努力奋斗啊!

我也马上要研究生实习了,希望不论以后自己做什么,都能保留一份让自己神清气爽的后花园~
原创粉丝点击