将自定义消息标头添加到从Windows Mobile 6客户端使用的WCF服务中 [英] Adding custom message header to a WCF service which is consumed from Windows Mobile 6 client
问题描述
我有一个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屋!