Desenvolvimento - WCF/WPF
UserName e Password em serviços WCF para Silverlight
Como sabemos, podemos utilizar usuário e senha para autenticar um usuário em um serviço WCF, mas há algumas regras que precisam ser seguidas.
por Israel AéceComo sabemos, podemos utilizar usuário e senha para autenticar um usuário em um serviço WCF, mas há algumas regras que precisam ser seguidas, como eu já comentei neste post. Uma dessas regras é que não podemos trafegar essas informações sem alguma criptografia. Mesmo que o serviço seja exposto via HTTP, a utilização de um certificado (não do HTTPS), fará este papel.
Eu mostrei como customizar a autenticação neste artigo, e note que estou usando um certificado e o serviço não está disponível através do HTTPS. Além disso,o binding que está sendo utilizado é o WSHttpBinding, que sabe como efetuar a criptografia das informações. Agora imagine que este serviço pode ser consumido por uma aplicação Silverlight. Infelizmente o WCF do Silverlight não tem suporte ao WSHttpBinding, somente ao BasicHttpBinding, e mais recentemente, via NetTcpBinding.
Mas como podemos proceder neste caso? Para poder disponibilizar serviços WCF para uma aplicação Silverlight, precisaremos recorrer a segurança em nível de transporte, para garantir a proteção. Para isso, estamos obrigados à expor o serviço através de HTTPS,e as credenciais estarão protegidas dentro da mensagem. Mas antes da versão 3.0 do Silverlight, era díficil expor e/ou consumir serviços WCF que exigem usuário e senha, já que você precisava criar headers customizados para acomodar essas informações, assim como era (ou ainda é) feito pelos ASP.NET Web Services.
A partir da versão 3.0, o Microsoft introduziu mais uma opção no binding BasicHttpBinding (do Silverlight), que é a TransportWithMessageCredential. Com esta opção definida, o serviço deverá ser disponibilizado via HTTPS, e as credencias viajarão dentro da mensagem, sem precisarmos escrever qualquer código adicional. Felizmente, quando efetuamos a referência em uma aplicação Silverlight, o proxy gerado já disponibiliza a propriedade ClientCredentials, onde podemos atribuir o usuário e senha, que eventualmente vem de controles TextBoxes da tela.
A configuração do serviço é relativamente simples. O primeiro passo é criar o validador customizado de usuários, que nada mais é do que uma classe que herda de UserNamePasswordValidator, e dentro do método Validate, você escreve a regra para buscar e validar o usuário. Para maiores detalhes de como isso funciona, consulte este artigo. Depois note também que definimos a segurança como sendo TransportWithMessageCredential, conforme comentamos acima.
<system.serviceModel>
<services>
<service name="ServicoDeClientes"
behaviorConfiguration="bhr">
<endpoint name="srv"
binding="basicHttpBinding"
contract="IContrato"
bindingConfiguration="bc"/>
</service>
</services>
<bindings>
<basicHttpBinding>
<binding name="bc">
<security mode="TransportWithMessageCredential"/>
</binding>
</basicHttpBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior name="bhr">
<serviceMetadata httpsGetEnabled="true"/>
<serviceCredentials>
<userNameAuthentication
customUserNamePasswordValidatorType="ValidadorDeUsuarios"
userNamePasswordValidationMode="Custom"/>
</serviceCredentials>
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
Depois da configuração do serviço, o publicamos e, consequentemente, referenciamos na aplicação cliente (Silverlight). Ao referenciá-lo, já podemos notar que o arquivo de configuração já está devidamente especificado com a mesma opção de segurança: TransportWithMessageCredential.
<configuration>
<system.serviceModel>
<client>
<endpoint address="https://localhost/SLTest/ServicoDeClientes.svc"
binding="basicHttpBinding"
bindingConfiguration="srv"
contract="ServicoDeClientes.IContrato"
name="srv" />
</client>
<bindings>
<basicHttpBinding>
<binding name="srv">
<security mode="TransportWithMessageCredential" />
</binding>
</basicHttpBinding>
</bindings>
</system.serviceModel>
</configuration>
Com isso, tudo o que nos resta éinstanciar o proxy e definir a propriedade ClientCredentials, que receberá os credenciais do usuário. Depois de configurado, você já está apto a chamar qualquer operação exposta pelo serviço, que antes dela ser efetivamente executada, o runtime do WCF avaliará as credenciais informadas, se certfificando de que são válidas, e somente a partir daí, irá invocar o método.
ServicoDeClientes.ContratoClient p =new ServicoDeClientes.ContratoClient();
p.ClientCredentials.UserName.UserName = this.Login.Text;
p.ClientCredentials.UserName.Password = this.Password.Text;
p.PingCompleted += (s, args) => this.textBlock1.Text = args.Result;
p.PingAsync();
A chamada da operação de forma assíncrona, nada tem nada a ver com a questão de segurança. Isso é apenas uma característica do WCF do Silverlight, e mesmo que não houvesse qualquer nível de segurança envolvido, a forma para invocar uma operação seria a mesma.
Eu mostrei como customizar a autenticação neste artigo, e note que estou usando um certificado e o serviço não está disponível através do HTTPS. Além disso,o binding que está sendo utilizado é o WSHttpBinding, que sabe como efetuar a criptografia das informações. Agora imagine que este serviço pode ser consumido por uma aplicação Silverlight. Infelizmente o WCF do Silverlight não tem suporte ao WSHttpBinding, somente ao BasicHttpBinding, e mais recentemente, via NetTcpBinding.
Mas como podemos proceder neste caso? Para poder disponibilizar serviços WCF para uma aplicação Silverlight, precisaremos recorrer a segurança em nível de transporte, para garantir a proteção. Para isso, estamos obrigados à expor o serviço através de HTTPS,e as credenciais estarão protegidas dentro da mensagem. Mas antes da versão 3.0 do Silverlight, era díficil expor e/ou consumir serviços WCF que exigem usuário e senha, já que você precisava criar headers customizados para acomodar essas informações, assim como era (ou ainda é) feito pelos ASP.NET Web Services.
A partir da versão 3.0, o Microsoft introduziu mais uma opção no binding BasicHttpBinding (do Silverlight), que é a TransportWithMessageCredential. Com esta opção definida, o serviço deverá ser disponibilizado via HTTPS, e as credencias viajarão dentro da mensagem, sem precisarmos escrever qualquer código adicional. Felizmente, quando efetuamos a referência em uma aplicação Silverlight, o proxy gerado já disponibiliza a propriedade ClientCredentials, onde podemos atribuir o usuário e senha, que eventualmente vem de controles TextBoxes da tela.
A configuração do serviço é relativamente simples. O primeiro passo é criar o validador customizado de usuários, que nada mais é do que uma classe que herda de UserNamePasswordValidator, e dentro do método Validate, você escreve a regra para buscar e validar o usuário. Para maiores detalhes de como isso funciona, consulte este artigo. Depois note também que definimos a segurança como sendo TransportWithMessageCredential, conforme comentamos acima.
<system.serviceModel>
<services>
<service name="ServicoDeClientes"
behaviorConfiguration="bhr">
<endpoint name="srv"
binding="basicHttpBinding"
contract="IContrato"
bindingConfiguration="bc"/>
</service>
</services>
<bindings>
<basicHttpBinding>
<binding name="bc">
<security mode="TransportWithMessageCredential"/>
</binding>
</basicHttpBinding>
</bindings>
<behaviors>
<serviceBehaviors>
<behavior name="bhr">
<serviceMetadata httpsGetEnabled="true"/>
<serviceCredentials>
<userNameAuthentication
customUserNamePasswordValidatorType="ValidadorDeUsuarios"
userNamePasswordValidationMode="Custom"/>
</serviceCredentials>
</behavior>
</serviceBehaviors>
</behaviors>
</system.serviceModel>
Depois da configuração do serviço, o publicamos e, consequentemente, referenciamos na aplicação cliente (Silverlight). Ao referenciá-lo, já podemos notar que o arquivo de configuração já está devidamente especificado com a mesma opção de segurança: TransportWithMessageCredential.
<configuration>
<system.serviceModel>
<client>
<endpoint address="https://localhost/SLTest/ServicoDeClientes.svc"
binding="basicHttpBinding"
bindingConfiguration="srv"
contract="ServicoDeClientes.IContrato"
name="srv" />
</client>
<bindings>
<basicHttpBinding>
<binding name="srv">
<security mode="TransportWithMessageCredential" />
</binding>
</basicHttpBinding>
</bindings>
</system.serviceModel>
</configuration>
Com isso, tudo o que nos resta éinstanciar o proxy e definir a propriedade ClientCredentials, que receberá os credenciais do usuário. Depois de configurado, você já está apto a chamar qualquer operação exposta pelo serviço, que antes dela ser efetivamente executada, o runtime do WCF avaliará as credenciais informadas, se certfificando de que são válidas, e somente a partir daí, irá invocar o método.
ServicoDeClientes.ContratoClient p =new ServicoDeClientes.ContratoClient();
p.ClientCredentials.UserName.UserName = this.Login.Text;
p.ClientCredentials.UserName.Password = this.Password.Text;
p.PingCompleted += (s, args) => this.textBlock1.Text = args.Result;
p.PingAsync();
A chamada da operação de forma assíncrona, nada tem nada a ver com a questão de segurança. Isso é apenas uma característica do WCF do Silverlight, e mesmo que não houvesse qualquer nível de segurança envolvido, a forma para invocar uma operação seria a mesma.
- WCF – Gerenciamento de InstânciaWCF
- Gerando Gráficos com Silverlight, WCF e LINQSilverlight
- Criando e consumindo serviços com WCFWCF
- Usando Timer no WPF e SilverlightSilverlight
- Utilizando WCF-Provided HostWCF/WPF