Id密码、自定义验证的自托管安全 WCF






4.90/5 (14投票s)
无需配置文件 – 所有设置都在代码中,无需 IIS – 自托管,通过通道工厂消费
引言
自托管安全 WCF 自定义验证,无需配置文件 – 所有设置都在代码中,无需 IIS – 自托管,通过通道工厂消费
背景
最近我遇到了一种情况,需要在没有 IIS 的环境中创建一个安全的 WCF POC,并且我们只有 VS 2010 Express。我们需要创建一个完全自给自足的 POC,因此不需要证书。
解决方案是创建一个自托管的 WCF 服务,使用自定义验证并使用通道工厂进行消费。在创建这个 POC 的过程中,我遇到了一些错误,然后开始在互联网上搜索类似的 POC,我找到了一些,但大多数都不能直接运行,例如只有服务器端代码,只有客户端,或者需要在 app.config 中进行一些修改。
WCF 服务器端
自托管(控制台)WCF 服务,传输安全(ID/密码)
using System;
using System.ServiceModel;
using System.ServiceModel.Security;
using System.IdentityModel.Tokens;
using System.IdentityModel.Selectors;
using System.Security.Principal;
using System.ServiceModel.Description;
namespace SecurWCFSelfHosting
{
class Program
{
[ServiceContract]
public interface IDemoService
{
[OperationContract]
int Add(int x, int y);
}
public class DemoService : IDemoService
{
public int Add(int x, int y)
{
return x + y;
}
}
static void Main(string[] args)
{
// This is a address of our service
Uri httpUrl = new Uri("https://:999/MyService/");
//Create ServiceHost
ServiceHost host = new ServiceHost(typeof(DemoService), httpUrl);
/// Set behaviour of **binding**
BasicHttpBinding http = new BasicHttpBinding();
//1. set Mode TransportCredentialOnly = no httpS
http.Security.Mode = BasicHttpSecurityMode.TransportCredentialOnly;
//2. Transport security Basic = user id and password
http.Security.Transport.ClientCredentialType = HttpClientCredentialType.Basic;
///** Set behaviour of **host**
//Add a service endpoint
host.AddServiceEndpoint(typeof(IDemoService), http, "");
host.Credentials.UserNameAuthentication.UserNamePasswordValidationMode = UserNamePasswordValidationMode.Custom;
host.Credentials.UserNameAuthentication.CustomUserNamePasswordValidator = new MyCustomValidator();
// checking and publishing meta data
ServiceMetadataBehavior smb = host.Description.Behaviors.Find<ServiceMetadataBehavior>();
if (smb == null)
{
smb = new ServiceMetadataBehavior();
smb.HttpGetEnabled = true;
host.Description.Behaviors.Add(smb);
}
//Start the Service
host.Open();
Console.WriteLine(DateTime.Now.ToString()+" Service is host at " + httpUrl.ToString());
Console.WriteLine("The service is running in the following account: {0}", WindowsIdentity.GetCurrent().Name);
Console.WriteLine("Press <ENTER> to terminate service.");
Console.ReadLine();
}
}
public class MyCustomValidator : UserNamePasswordValidator
{
public override void Validate(string userName, string password)
{
//For Demo only here you can add logic to validate ID,Pwd in AD or DB
if ((userName != "h") || (password != "p"))
{
throw new SecurityTokenException("Him:) Validation Failed!");
}
Console.WriteLine(DateTime.Now.ToString()+" Validation success for user :"+ userName);
}
}
}
客户端
在控制台应用程序中消费,使用通道工厂
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.ServiceModel;
using System.ServiceModel.Description;
/// svcuti. @ C:\Program Files\Microsoft SDKs\Windows\v7.0A\bin
namespace WCFConsumeByChannelFactory
{
class Program
{
static void Main(string[] args)
{
EndpointAddress Serviceaddress = new EndpointAddress("https://:999/MyService/");
/// Set behaviour of **binding** Same setting as ##Server##
BasicHttpBinding httpBinding = new BasicHttpBinding();
httpBinding.Security.Mode = BasicHttpSecurityMode.TransportCredentialOnly;
httpBinding.Security.Transport.ClientCredentialType = HttpClientCredentialType.Basic;
ChannelFactory<IDemoService> myChannelFactory =
new ChannelFactory<IDemoService>(httpBinding, Serviceaddress);
var defaultCredentials = myChannelFactory.Endpoint.Behaviors.Find<ClientCredentials>();
//#1 IF this dosen not work then try #2
myChannelFactory.Credentials.UserName.UserName = "h";
myChannelFactory.Credentials.UserName.Password = "p";
///#2
//ClientCredentials CC = new ClientCredentials();
//CC.UserName.UserName = "h";
//CC.UserName.Password = "p";
// myChannelFactory.Endpoint.Behaviors.Remove(defaultCredentials); //remove default ones
// myChannelFactory.Endpoint.Behaviors.Add(CC); //add required on
// Create a channel.
IDemoService wcfClient1 = myChannelFactory.CreateChannel();
double s = wcfClient1.Add(73, 22);
Console.WriteLine(s.ToString());
((IClientChannel)wcfClient1).Close();
Console.ReadKey();
}
}
}
所有这些代码都包含在附件的 zip 文件中。
关注点
在互联网上搜索时,我找到了这个:如何:使用通道工厂异步调用操作 http://msdn.microsoft.com/en-us/library/bb885132.aspx
绑定摘要