将自定义消息标头添加到从Windows Mobile 6客户端使用的WCF服务中 [英] Adding custom message header to a WCF service which is consumed from Windows Mobile 6 client

查看:35
本文介绍了将自定义消息标头添加到从Windows Mobile 6客户端使用的WCF服务中的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个WCF服务应用程序,该服务器可用于不同类型的客户端.在调用服务方法时,我想在服务头中发送一些特殊信息.

I have a WCF Service Application which server to different type of clients. While calling the service methods I want to send some spesific information within the service header.

虽然使用的是.NET Framework的较新版本,但我可以使用MessageHeader处理这种情况.由于消费者可以将服务视为WCF服务,所以没有问题.

While using a newer version of .NET Framework I can handle the situation using MessageHeader. Since the consumer can see the service as WCF Service there is no problem.

[DataContract]
public class AuthToken
{
    [DataMember]
    public string Username { get; set; }
    [DataMember]
    public string Password { get; set; }
}

客户端:

AuthWCFSvc.Service1Client client = new AuthWCFSvc.Service1Client();
using (OperationContextScope scope = new OperationContextScope(client.InnerChannel))
{
    SvcAuthClient.AuthWCFSvc.AuthToken token = new AuthWCFSvc.AuthToken();
    token.Username = "wcfuser";
    token.Password = "wcfpass";

    MessageHeader<SvcAuthClient.AuthWCFSvc.AuthToken> header = new MessageHeader<SvcAuthClient.AuthWCFSvc.AuthToken>(token);
    var untyped = header.GetUntypedHeader("Identity", "http://www.my-website.com");
    OperationContext.Current.OutgoingMessageHeaders.Add(untyped);

    client.TestHeader();
}

服务器端:

MessageHeaders headers = OperationContext.Current.IncomingMessageHeaders;
AuthToken token = headers.GetHeader<AuthToken>("Identity", "http://www.my-website.com");

但是,有些带有.NET Framework 3.5 Compact Edition的Windows Mobile 6设备也使用这些服务.由于技术限制,他们只能将WCF服务作为Web服务进行处理.

But there are Windows Mobile 6 devices with .NET Framework 3.5 Compact Edition, using these services as well. Due to technological restrictions, they only can process the WCF services as Web Services.

如果客户端使用WCF服务作为Web服务,如何添加特殊的头信息并以服务方法解析头信息?

If a client is consuming a WCF service as Web Service how can add spesific header information and resolve the header information at the service method?

推荐答案

如您所知,在.NET CF 3.5上,您只能将WCF用作SOAP方式上的标准Web服务.因此,您不能使用任何WCF本机安全性资源.

As you know, on .NET CF 3.5 you can only use WCF as standard webservice on SOAP way. Therefore, you can't use any of WCF native security resources.

我想出了如何使用基本Http身份验证,可以配置客户端和服务器端,我可以解释如下:

I figured out how to use Basic Http Authentication, configuring client and server sides and I can explain it as follows:

在客户端(使用.Net CF 3.5的设备上),这很容易.只需使用以下信息通知您的凭据即可配置clientServiceProxy:

On client side (on your device with .Net CF 3.5), its easy. Just inform your credentials configuring your clientServiceProxy by using:

 var service = new YourServiceNamespace.YourService();
 service.Credentials = new NetworkCredential("login", "12345");
 service.PreAuthenticate = true;

这将使您的客户端处理服务器响应中的"WWW-Authenticate"标头,并通过响应标头"Authorization:Basic"自动传递您的凭据.

This will make your client deal with the "WWW-Authenticate" header from the server response and pass your credentials automatically via the response header "Authorization: Basic".

在web.config上的WCF配置上,您应该只为传输配置安全性,并使用HTTPS(这足以保护您的邮件免遭嗅探器攻击.)

On the WCF configuration on your web.config, you should configure security just for Transport, and use HTTPS (this is enough to protect your message from sniffers).

  <basicHttpBinding>
    <binding>
      <security mode="Transport">
        <transport clientCredentialType="None" />
      </security>
    </binding>
  </basicHttpBinding>

现在,由于WCF不支持基本Http身份验证,因此我们必须使用自定义HTTP模块来处理它.

Now, as WCF doesn't has native support for Basic Http Authentication, we have to use a custom HTTP module to deal with it.

public class BasicHttpAuthentication : IHttpModule
{
    public delegate bool AuthenticateDelegate( string username, string password );

    public static AuthenticateDelegate AuthenticateMethod;

    public void Dispose() { }

    public void Init( HttpApplication application )
    {
        application.AuthenticateRequest += this.OnAuthenticateRequest;
        application.EndRequest += this.OnEndRequest;
    }

    private void DenyAccess( HttpApplication app )
    {
        app.Response.StatusCode = 401;
        app.Response.StatusDescription = "Access Denied";

        // Write to response stream as well, to give user visual 
        // indication of error during development
        app.Response.Write( "401 Access Denied" );

        app.CompleteRequest();
    }

    private void OnAuthenticateRequest( object source, EventArgs eventArgs )
    {
        if ( AuthenticateMethod == null )
            return;

        var app = ( HttpApplication )source;

        //the Authorization header is checked if present
        string authHeader = app.Request.Headers["Authorization"];
        if ( !string.IsNullOrEmpty( authHeader ) )
        {
            string authStr = app.Request.Headers["Authorization"];

            if ( string.IsNullOrEmpty( authStr ) )
                return; // No credentials; anonymous request

            authStr = authStr.Trim();
            if ( authStr.IndexOf( "Basic", 0 ) != 0 )
                // header is not correct...we'll pass it along and 
                // assume someone else will handle it
                return;

            authStr = authStr.Trim();

            string encodedCredentials = authStr.Substring( 6 );

            byte[] decodedBytes = Convert.FromBase64String( encodedCredentials );
            string s = new ASCIIEncoding().GetString( decodedBytes );

            string[] userPass = s.Split( new[] { ':' } );
            string username = userPass[0];
            string password = userPass[1];

            if ( !AuthenticateMethod( username, password ) )
                this.DenyAccess( app );
        }
        else
        {
            app.Response.StatusCode = 401;
            app.Response.End();
        }
    }

    private void OnEndRequest( object source, EventArgs eventArgs )
    {
        //the authorization header is not present
        //the status of response is set to 401 and it ended
        //the end request will check if it is 401 and add
        //the authentication header so the client knows
        //it needs to send credentials to authenticate
        if ( HttpContext.Current.Response.StatusCode == 401 )
        {
            HttpContext context = HttpContext.Current;
            context.Response.StatusCode = 401;
            context.Response.AddHeader( "WWW-Authenticate", "Basic Realm=\"Please inform your credentials\"" );
        }
    }
}

要启用HTTP模块,请将以下内容添加到system.webServer部分中的web.config文件中:

To enable the HTTP module, add the following to your web.config file in the system.webServer section:

<system.webServer>
    <modules>
      <add name="BasicHttpAuthentication" 
        type="BasicHttpAuthentication, YourAssemblyName"/>
    </modules>

现在,您必须通知模块一个用于验证来自客户端的凭证的功能.您会看到模块内有一个名为"AuthenticateMethod"的静态委托,因此您可以将Global.asax通知给Application_Start上的一个函数:

Now you have to inform to the module a Function to use for validating the credentials from the client. You can see that there's a static delegate inside the module called "AuthenticateMethod", so you can inform a function on your Application_Start of your global.asax:

BasicHttpAuthentication.AuthenticateMethod = ( username, password ) => username == "login" && password == "12345";

这篇关于将自定义消息标头添加到从Windows Mobile 6客户端使用的WCF服务中的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆