将自定义消息头添加到从 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 服务的主要内容,如果未能解决你的问题,请参考以下文章
使用 Azure 服务结构的默认客户端时如何将消息头添加到请求中?
如何将自定义消息添加到 Firebase Google 身份验证弹出窗口?
使用stanza.io将自定义属性添加到不在服务器上的存档表中存储消息的消息