WebServices usando soapHeader
Um pouco mais de segurança na
autenticação do usuário
Neste artigo, gostaria de mostrar como criar um webservices seguro, ou seja, utilizando token, usuário, senha e soapHeader. Assim fica melhor do que colocar como parâmetro de entrada usuário e senha. Fica um pouco mais escondido do que o normal, porém não é tão seguro assim caso os mesmos não estiverem criptografados, utilizando SSL e outras coisas mais.
É lógico que ajuda colocar os dados no soapHeader, fica melhor do que vindo como parâmetro de entrada de um método porque não fica à vista. É importante dizer que não é só isso que faz um webservices ficar seguro.
Requisitos:
Ferramenta: Visual Studio.NET 2008 Team System
Framework: Versão 3.5
Tecnologia: WebService / SOA
Partes que não vou mostrar no
artigo.
A camada responsável pelo acesso ao banco de dados. Lembrando que, a melhor forma de utilizar o acesso a dados é usando MVC com interface e tudo de direito. Não fiz como MVC ainda, preciso primeiro mostrar a criação simples e depois complicar mais um pouco com camadas.
WebServices, para que serve?
Com o surgimento do software, sistemas e sites; começou a ter a necessidade de vincular dados entre eles; ou seja; comunicação entre sistemas de plataformas diferentes. Os dados precisam ser passados de um lado para outro de forma dinâmica e personalizada. Antigamente, os dados eram colocados em um arquivo .txt e mandados via e-mail, mandados via upload e outros.
Existia um problema nesse envio de arquivo, isso porque não tinha um padrão entre os desenvolvedores ou sistemas que criavam esses arquivos. Era problemático a leitura desses arquivos porque a coisa era posicional, ou seja, tinha que contar posição a posição para pegar os dados. Qualquer mudança da posição de dado era prejudicado todo o sistema de leitura e gravação.
Respondendo a pergunta, o webservices serve para facilitar a comunicação entre sistemas de forma mais simples e padronizada.
Qualquer linguagem pode usar?
Qualquer linguagem que utiliza ou tem suporte de leitura de xml ou qualquer outra coisa com xml poder utilizar ou “consumir” um webservices. Linguagem orientada a objetos, estruturada, tudo acessa e tem capacidade de criar e consumir um serviço na web.
Qual a forma incorreta de
usar WebServices?
No meu ponto de vista, um serviço web é tão quão importante como um sistema cliente / servidor ou web. Muitas empresas deixam de considerar esse tipo de coisa e trata como uma coisa qualquer, não pode ser assim.
Utilizar o serviço web com endereço http normalmente é um erro; deve ser feito utilizando https. Não usar criptografia nos dados importantes como: usuário, senha, token e outros é uma forma incorreta de utilizar serviço web.
Colocar parâmetro de entrada como “senha” é uma forma incorreta de utilizar o serviço web. A melhor forma é usar no soapHeader por ficar mais escondido.
Retornar tipo de dado que apenas uma linguagem utiliza, por exemplo: object “DataSet”. Um objeto criado pela Microsoft e usado apenas pela mesma. Caso uma outra linguagem ou plataforma for consumir o serviço, o seu retorno será ilegível. Exemplo: Java J2EE, Payton, C++, C e outros.
Desenvolvimento do aplicativo
Depois de ter explicado um pouco sobre o que é, como funciona, como utilizar e não fazer, passo para a etapa de criar um serviço web e consumí-lo de forma mais simples e fácil. Utilizei o mesmo exemplo do artigo anterior chamado “WebService utilizando soapHeader e token” publicado no site.
Criei outro método e acrescentei outro dado no soapHeader necessário.
Imagem 1.1
Na imagem 1.1 mostro que o projeto chamado SoapHeader possui um serviço web chamado WebService1.asmx, uma página Default.aspx e uma Web References chamada wssseguro.
Classe de autenticação
Criei uma classe de autenticação, responsável pela autenticação e verificação de usuário, senha e token no soapHeader. Veja o code 1.1.
public class AuthenticationSoapHeader : SoapHeader
{ private string _devToken; private string _user; private string _pw; public string Pw { get { return _pw; } set { _pw = value; } } public string User { get { return _user; } set { _user = value; } } public string DevToken { get { return _devToken; } set { _devToken = value; } } public AuthenticationSoapHeader() { } public
AuthenticationSoapHeader(string devToken, string user, string pw) { _devToken = devToken; _user = user; _pw = pw; } } |
Code 1.1
Explicação:
A primeira coisa foi estender a classe de SoapHeader. (Code 1.2)
public class AuthenticationSoapHeader : SoapHeader |
Code 1.2
A segunda tarefa feita foi declarar variáveis para gerar as propriedades; referentes ao mesmo dado, usuário, senha e token. Gerei dois métodos construtores na classe, uma que não tem parâmetro de entrada e outra que tem três parâmetros de entrada; isso é necessário. (Code 1.3)
public AuthenticationSoapHeader() { } public
AuthenticationSoapHeader(string devToken, string user, string pw) { _devToken = devToken; _user = user; _pw = pw; } |
Code 1.3
Explicação:
Coloquei o construtor recebendo os três parâmetros e adicionando os mesmos as propriedades criadas para um melhor uso quem o chamar.
No artigo anterior, mostrei como verificar uma autenticação do usuário no banco de dados, esse artigo está publicado no site. Para explicar um pouco melhor, deixo usuário digitar a senha, gero um hash dela com um número aleatório e a senha gerada; depois gravo no banco de dados com esse número de controle, como se fosse um id de controle para cada usuário. Para a autenticação do usuário, basta pegar esse id de controle, pegar a senha que usuário digitou e comparar os dados, caso for verdadeiro, o mesmo logou sem qualquer problema.
Peguei esse artigo e gerei um serviço na web de autenticação e verificação de usuário. Os próximos passos são: gerar o método que cria um número aleatório para cada usuário e em seguida gerar um método que calcula hash.
/// <summary> /// Método que gerar numero aleatorio /// </summary> ///
<returns>int</returns> private int GerarNrAleatorio() { Random rnd = new Random(); return rnd.Next(); } |
Code 1.4
Gera um número aleatório com o Random().
/// <summary> /// Método que calcula hash dinâmica /// </summary> /// <param
name="input">por exemplo: password</param> ///
<returns>string</returns> private string CalcularHash(string
input) { MD5 md5 = System.Security.Cryptography.MD5.Create(); byte[] inputBytes =
System.Text.Encoding.ASCII.GetBytes(input); byte[] hash =
md5.ComputeHash(inputBytes); StringBuilder str = new
StringBuilder(); for (int i = 0; i < hash.Length;
i++) {
str.Append(hash[i].ToString("X2")); } return str.ToString(); } |
Code 1.5
Explicação:
Utilizei a classe Cryptography para gerar em Bytes a esse hash. Depois disso utilizei também o md5, fiz um for para gerar letra por letra.
O passo seguinte é gerar o um método público chamado AutenticarUsuario() sem qualquer parâmetro de entrada, porém dentro do mesmo é verificado todo o soapHeader.
Code 1.6
public object AutenticarUsuario() { if (ValidationSoap != null
&& ValidationSoap.User != null
&& ValidationSoap.Pw != null
&& ValidationSoap.DevToken != null)
{ //abro o banco de dados conn =
DTecDefination.GetHelper(); //toda regra para buscar o
usuario e autenticar string numero; StringBuilder str = new
StringBuilder(); str.Append("select
controle from tb_usuario where nome=@nome"); try { SqlCommand cmd = new
SqlCommand(str.ToString()); cmd.Parameters.Add("@nome",
SqlDbType.VarChar).Value = ValidationSoap.User; conn.GetSourceConnection(); DataSet dtSet =
conn.ExecutaDataSetParameter(cmd); if (dtSet != null) if
(dtSet.Tables[0].Rows.Count > 0) { numero =
dtSet.Tables[0].Rows[0]["controle"].ToString(); string hash =
CalcularHash(numero + ValidationSoap.Pw); StringBuilder
strHash = new StringBuilder();
strHash.Append("select chave from tb_usuario where senha =
@hashT"); SqlCommand
bdCommand = new SqlCommand(strHash.ToString()); bdCommand.Parameters.Add("@hashT",
SqlDbType.VarChar).Value = hash; object obj =
conn.ExecutaScalarParameter(bdCommand); if (obj != null) return obj; else return null; } else return null; else return null; } catch (Exception ex) { return null; } }
else return null;
} |
Code 1.6
Explicação:
A primeira coisa foi verificar se o ValidationSoap é diferente de null, em seguida verifiquei o User, Pw e DevToken. Abri o banco de dados, gerei o select no banco de dados, lembro que pode ser usado stored procedure sem qualquer problema. Depois executei o comando ExecutaDataSetParameter.
Verifiquei se trouxe algum dado no DataSet, calculei o Hash passando o número e a senha do usuário, caso for igual o método retorna um Object com o número do usuário. Caso queira gerar uma sessão para identificar o usuário e tudo mais. Compilei o código e ficou tudo ok. Preciso adicionar o webservice junto ao projeto. (Imagem 1.2)
Imagem 1.2
Cliquei com o botão direito em cima de Web References e escolhi a opção Add Web Referece....
Adicionei o endereço do localhost e dei um nome a ele. Lembro que o endereço é particular de cada um, isso porque cada projeto pode colocar uma porta diferente no momento. O endereço gerado pelo meu servidor de aplicação do Visual Studio .NET Team System (http://localhost:1189/webservice1.asmx). O nome adiciona do foi wsseguro.
Consumir WebService
Agora em diante, preciso consumir o webservice gerado na aplicação. Lembro que existe uma página default.aspx.cs no projeto. (Code 1.7)
protected void Page_Load(object
sender, EventArgs e) { wsseguro.WebService1 ws = new
SoapTeste.wsseguro.WebService1(); wsseguro.AuthenticationSoapHeader
soap = new SoapTeste.wsseguro.AuthenticationSoapHeader(); soap.DevToken = "123425"; soap.User = "mauricio"; soap.Pw = "mauricio"; ws.AuthenticationSoapHeaderValue =
soap; Object obj =
ws.AutenticarUsuario(); if (obj == null) { Response.Write("Usuário não autorizado"); } else { int numero = int.Parse(obj.ToString()); Response.Write("Usuario autorizado -" + numero); } } |
Code 1.7
Primeiro, criei uma instância do webservice, depois o soap. Adicionei os valores no soap e falei para o webservice gerado pela variável ws, o seu valor. O passo seguinte foi chamar o método AutenticarUsuario().
Depois precisei apenas verificar os dados para mostrar a mensagem na tela. (Imagem 1.3)
Imagem 1.3
Funcionou perfeitamente a autenticação e autorização do usuário logado. Dai em diante, a sua criatividade pode ser exercitada livremente. Caso coloque um usuário ou senha inválidos, ou mesmo o token, veja a mensagem que é apresentada na tela. (Imagem 1.4).
Imagem 1.4
Bom eu fico por aqui, qualquer dúvida favor entrar em contato.