Recentemente estive trabalhando com o
WCF (
Windows Communication Foundation) da
Microsoft. E depois de fazer algumas experiências básicas lá fui eu me certificar da forma de transmissão segura e criptografadas.
Não vou me alongar na explicação porque isso tem no
MSDN e em
n blogs melhores escritor do que o meu :-), mas, como de praxe vou registrar um exemplo aqui (cabe ressaltar que daria para refatorar um pouco esse meu exemplo, que eu tive que fazer as pressas, principalmente a classe Greetting.cs que ficou bem porca mesmo. Admito, sem orgulho :-| #ficaAdica).
Para quem não sabe o que é o WCF, aqui vai a definição da Microsoft:
Windows Communication Foundation (
WCF) is
Microsoft's unified programming model for building service-oriented applications. It enables developers to build secure, reliable, transacted solutions that integrate across platforms and interoperate with existing investments.
Sacou?
Então vamos ao que interessa: código!
Em meu exemplo eu criei uma classe chamada Credential.cs que irá armazenar um token (que no meu caso é uma senha) e a informação de que tipo de device está consumindo meu serviço.
Além disso, há uma classe onde a lógica do meu programa está implementada e outra classe que é o serviço em sí (a lógica do tratamento das chamadas ao serviço).
Simplão, o funcionamento é: conferir se a senha passada está correta e se estiver chamar a classe que vai gerar a saudação e retorná-la ao client, caso contrário é lançar uma exceção.
Para começar essa é a classe da credencial (Credential.cs):
using System;
using System.ServiceModel;
using System.Net.Security;
namespace com.blogspot.jeanjmichel.services
{
/// <summary>
/// This class represents the credential.
/// </summary>
[MessageContract]
public class Credential
{
/// <summary>
/// The token is a password that have be valid to authorize the
/// client to consume the service.
/// </summary>
[MessageHeader(ProtectionLevel = ProtectionLevel.EncryptAndSign)]
public String Token;
/// <summary>
/// The DeviceCategory is an inrelevant information that is not
/// encrypted and is just used to show the kind of device is
/// consuming the service (Whindows Phone, iOS, Android, web page,
/// etc).
/// </summary>
[MessageBodyMember(Order = 1, ProtectionLevel = ProtectionLevel.None)]
public String DeviceCategory;
/// <summary>
/// Empty constructor.
/// </summary>
public Credential()
{
}
}
}
Notem que a informação do token irá trafegar criptografada, no header da mensagem. Já a informação do device do client não irá trafegar criptografada.
Greeting.cs, este é o core, ou kernel, do programa, dependendo do quanto nojento você queira parecer falando isso :-) (roubei essa do
Elemar Jr):
using System;
using System.ServiceModel;
using System.Net.Security;
namespace com.blogspot.jeanjmichel.model
{
/// <summary>
/// This class represents a greeting.
/// </summary>
[MessageContract]
public class Greeting
{
private String userGreeting;
/// <summary>
/// This method will set an appropriate greeting based on the server's
/// local time.
/// </summary>
private void SetGreeting()
{
DateTime now = DateTime.Now;
if (now.Hour >= 7 && now.Hour <= 11)
{
this.userGreeting = "Good morning";
}
else if (now.Hour >= 12 && now.Hour <= 17)
{
if (now.Hour == 12 || now.Hour == 13)
{
this.userGreeting = "Good afternoon, it's lunch time!";
}
else
{
this.userGreeting = "Good afternoon";
}
}
else if (now.Hour >= 18 && now.Hour <= 20)
{
this.userGreeting = "Good evening";
}
else
{
this.userGreeting = "Good night";
}
}
/// <summary>
/// This property returns the greeting in the message body,
/// and this will move across the network ever encrypted.
/// </summary>
[MessageBodyMember(Order = 1, ProtectionLevel = ProtectionLevel.EncryptAndSign)]
public String UserGreeting
{
get { return this.userGreeting; }
}
/// <summary>
/// Empty constructor.
/// </summary>
public Greeting()
{
this.SetGreeting(); //Call the method on construction time.
}
}
}
Fica a dica para quem quiser refatorar essa classe: usar internacionalização para retornar a saudação em
n idiomas.
E por fim, mas não menos importante :-), a interface (contrato) do serviço e a implementação dele:
using System.ServiceModel;
using com.blogspot.jeanjmichel.model;
namespace com.blogspot.jeanjmichel.services.contract
{
/// <summary>
/// This interface defines the service methods.
/// </summary>
[ServiceContract(Namespace = "http://jeanjmichel.blogspot.com/services/v0.0.1")]
public interface IGetGreeting
{
/// <summary>
/// This method will returns a greeting based based on the server's
/// local time.
/// </summary>
/// <param name="credential">An access credential that will be validated
/// in order to authorize the access to the
/// method.</param>
/// <returns>A Greeting object.</returns>
[OperationContract]
Greeting GetGreeting(Credential credential);
}
}
using System;
using System.ServiceModel;
using com.blogspot.jeanjmichel.services.contract;
using com.blogspot.jeanjmichel.model;
namespace com.blogspot.jeanjmichel.services
{
/// <summary>
/// This class is the service. Is where the logic behind the services'
/// calls occurs (validade credencial, invoke the business layer, etc).
/// </summary>
[ServiceBehavior(InstanceContextMode = InstanceContextMode.PerCall,
Namespace = "http://jeanjmichel.blogspot.com/services/v0.0.1")]
public class GetGreetingService: IGetGreeting
{
/// <summary>
/// This method will returns a greeting based based on the server's
/// local time.
/// </summary>
/// <param name="credential">An access credential that will be validated
/// in order to authorize the access to the
/// method.</param>
/// <returns>A Greeting object.</returns>
public Greeting GetGreeting(Credential credential)
{
if (String.IsNullOrEmpty(credential.Token))
{
throw new FaultException("Inform the security phrase," +
" and try again.");
}
else
{
if (credential.Token.Equals("mySeCuriTyP@ss"))
{
Greeting g = new Greeting();
return g;
}
else
{
throw new FaultException("Wrong password.");
}
}
}
}
}
Só falta configurar a aplicação no app.config, na tag <endpoint> o atributo binding de basicHttpBinding por wsHttpBinding:
<?xml version="1.0" encoding="utf-8" ?>
<configuration>
<system.web>
<compilation debug="true" />
</system.web>
<system.serviceModel>
<services>
<service name="GetGreetingService">
<host>
<baseAddresses>
<add baseAddress = "http://localhost:8081/soa" />
</baseAddresses>
</host>
<endpoint address =""
binding="wsHttpBinding"
contract="com.blogspot.jeanjmichel.services.contract.IGetGreeting"
bindingNamespace="http://jeanjmichel.blogspot.com/services/v0.0.1" >
<identity>
<dns value="localhost"/>
</identity>
</endpoint>
<endpoint address="mex" binding="mexHttpBinding" contract="IMetadataExchange"/>
</service>
</services>
<behaviors>
<serviceBehaviors>
<behavior>
<useRequestHeadersForMetadataAddress>
<defaultPorts>
<add scheme="http" port="8010" />
</defaultPorts>
</useRequestHeadersForMetadataAddress>
<serviceMetadata httpGetEnabled="True"/>
<serviceDebug includeExceptionDetailInFaults="True" />
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
</configuration>
Agora o client para consumir o serviço:
using ConsoleClient.GetGreetingService;
using System;
using System.ServiceModel;
namespace ConsoleClient
{
public class Program
{
static void Main(string[] args)
{
Console.WriteLine("Connecting to the endpoint...");
ChannelFactory<IGetGreeting> factory =
new ChannelFactory<IGetGreeting>("WSHttpBinding_IGetGreeting",
new EndpointAddress("http://192.168.0.173:8081/soa/GetGreetingService.svc"));
Console.WriteLine("Creating the proxy...");
IGetGreeting proxy = factory.CreateChannel();
Console.WriteLine("Creating the credential...");
Credential credential = new Credential();
credential.Token = "mySeCuriTyP@ss";
credential.DeviceCategory = "Windows Phone 7.8";
try
{
Console.WriteLine("Call the service...");
Greeting greeting = proxy.GetGreeting(credential);
Console.WriteLine("Greeting: " + greeting.UserGreeting);
}
catch (Exception e)
{
Console.WriteLine("An error has occurred. Message: " + e.Message);
}
Console.ReadKey();
}
}
}
Rodando esse client assim como está aqui a saída seria:
Connecting to the endpoint...
Creating the proxy...
Creating the credential...
Call the service...
Greeting: Good evening
Se você errar a senha:
Connecting to the endpoint...
Creating the proxy...
Creating the credential...
Call the service...
An error has occurred. Message: Wrong password.
E se você anular a senha:
Connecting to the endpoint...
Creating the proxy...
Creating the credential...
Call the service...
An error has occurred. Message: Inform the security phrase, and try again.
Vale ressaltar que eu estou hospedando a aplicação em um IIS local para testes.
Era isso. Qualquer dúvida é só comentar.