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.