将自定义消息头添加到从 Windows Mobile 6 客户端使用的 WCF 服务

Posted

技术标签:

【中文标题】将自定义消息头添加到从 Windows Mobile 6 客户端使用的 WCF 服务【英文标题】:Adding custom message header to a WCF service which is consumed from Windows Mobile 6 client 【发布时间】:2014-08-16 01:59:17 【问题描述】:

我有一个 WCF 服务应用程序,它为不同类型的客户端提供服务器。在调用服务方法时,我想在服务标头中发送一些特殊信息。

在使用较新版本的 .NET Framework 时,我可以使用 MessageHeader 来处理这种情况。由于消费者可以将服务视为 WCF 服务,因此没有问题。

[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 服务处理。

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

【问题讨论】:

我很想得到这些信息。找不到任何关于此的内容。如果您遇到(或已经遇到)解决方案,如果您能告诉我,我将非常高兴! 【参考方案1】:

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

我想出了如何使用Basic Http Authentication,配置客户端和服务器端,我可以解释如下:


客户端

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

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

这将使您的客户端处理来自服务器响应的“WWW-Authenticate”标头,并通过响应标头“授权:基本”自动传递您的凭据。


服务器端

在 web.config 的 WCF 配置中,您应该只为 Transport 配置安全性,并使用 HTTPS(这足以保护您的消息免受嗅探器的攻击)。

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

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

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 模块,请将以下内容添加到您的 web.config 文件的 system.webServer 部分:

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

现在您必须通知模块一个用于验证来自客户端的凭据的函数。您可以看到模块内有一个名为“AuthenticateMethod”的静态委托,因此您可以通知您的 Application_Start 上的一个函数您的 global.asax:

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

【讨论】:

以上是关于将自定义消息头添加到从 Windows Mobile 6 客户端使用的 WCF 服务的主要内容,如果未能解决你的问题,请参考以下文章

如何将自定义消息添加到 Jest 期望?

使用 Azure 服务结构的默认客户端时如何将消息头添加到请求中?

如何将自定义消息添加到 Firebase Google 身份验证弹出窗口?

使用stanza.io将自定义属性添加到不在服务器上的存档表中存储消息的消息

我们可以通过 mqtt 桥将自定义消息属性发布设置为 pubsub

如何将自定义 CA Root 证书添加到 Windows 中 pip 使用的 CA Store?