Dev (Back & Front)ARTIGO

WebServices usando soapHeader – segurança na autenticação do usuário

Neste artigo, quero 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 estejam 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, surgiu também 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, via upload e outros.

Havia um problema nesse envio de arquivo, porque não existia um padrão entre os desenvolvedores ou sistemas que os criavam. A leitura deles era problemática pois 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  prejudicava todo o sistema de leitura e gravação.

Respondendo à pergunta, o webservices serve para facilitar a comunicação entre sistemas de forma mais simples e padronizada.

Pode-se usar qualquer linguagem pode usar?

Qualquer linguagem que utilize ou tenha 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 isso e tratam 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 consumi-lo de forma mais simples e fácil. Utilizei o mesmo exemplo do artigo anterior chamado “Usando SoapHeader – segurança em webservice”. Criei outro método e acrescentei outro dado necessários no soapHeader.

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<br />    {<br />        private string _devToken;<br />        private string _user;<br />        private string _pw;<br /><br />        public string Pw<br />        {<br />            get { return _pw; }<br />            set { _pw = value; }<br />        }<br /><br />        public string User<br />        {<br />            get { return _user; }<br />            set { _user = value; }<br />        }<br /><br />        public string DevToken<br />        {<br />            get { return _devToken; }<br />            set { _devToken = value; }<br />        }<br /><br />        public AuthenticationSoapHeader() { }<br /><br />        public AuthenticationSoapHeader(string devToken, string user, string pw)<br />        {<br />            _devToken = devToken;<br />            _user = user;<br />            _pw = pw;<br />        }<br />    }

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 outro que tem três parâmetros de entrada. Isso é necessário (Code 1.3).

       public AuthenticationSoapHeader() { }<br /><br />        public AuthenticationSoapHeader(string devToken, string user, string pw)<br />        {<br />            _devToken = devToken;<br />            _user = user;<br />            _pw = pw;<br />        }

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. Para explicar um pouco melhor, deixo o 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 seja 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><br />        /// Método que gerar numero aleatorio<br />        /// </summary><br />        /// <returns>int</returns><br />        private int GerarNrAleatorio()<br />        {<br />            Random rnd = new Random();<br />            return rnd.Next();<br />        }

Code 1.4

Gerar um número aleatório com o Random().

        /// <summary><br />        /// Método que calcula hash dinâmica<br />        /// </summary><br />        /// <param name="input">por exemplo: password</param><br />        /// <returns>string</returns><br />        private string CalcularHash(string input)<br />        {<br />            MD5 md5 = System.Security.Cryptography.MD5.Create();<br />            byte[] inputBytes = System.Text.Encoding.ASCII.GetBytes(input);<br />            byte[] hash = md5.ComputeHash(inputBytes);<br /><br />            StringBuilder str = new StringBuilder();<br />            for (int i = 0; i < hash.Length; i++)<br />            {<br />                str.Append(hash[i].ToString("X2"));<br />            }<br />            return str.ToString();<br />        }

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.

        public object AutenticarUsuario()<br />        {<br />            if (ValidationSoap != null &&<br />                ValidationSoap.User != null &&<br />                ValidationSoap.Pw != null &&<br />                ValidationSoap.DevToken != null)<br />            {<br />                //abro o banco de dados<br />                conn = DTecDefination.GetHelper();<br /><br />                //toda regra para buscar o usuario e autenticar<br />                string numero;<br />                StringBuilder str = new StringBuilder();<br />                str.Append("select controle from tb_usuario where nome=@nome");<br /><br />                try<br />                {<br />                    SqlCommand cmd = new SqlCommand(str.ToString());<br />                    cmd.Parameters.Add("@nome", SqlDbType.VarChar).Value = ValidationSoap.User;<br /><br />                    conn.GetSourceConnection();<br />                    DataSet dtSet = conn.ExecutaDataSetParameter(cmd);<br /><br />                    if (dtSet != null)<br />                        if (dtSet.Tables[0].Rows.Count > 0)<br />                        {<br />                            numero = dtSet.Tables[0].Rows[0]["controle"].ToString();<br />                            string hash = CalcularHash(numero + ValidationSoap.Pw);<br /><br />                            StringBuilder strHash = new StringBuilder();<br />                            strHash.Append("select chave from tb_usuario where senha = @hashT");<br /><br />                            SqlCommand bdCommand = new SqlCommand(strHash.ToString());<br />                            bdCommand.Parameters.Add("@hashT", SqlDbType.VarChar).Value = hash;<br /><br />                            object obj = conn.ExecutaScalarParameter(bdCommand);<br /><br />                            if (obj != null)<br />                                return obj;<br />                            else<br />                                return null;<br />                        }<br />                        else<br />                            return null;<br />                    else<br />                        return null;<br />                }<br />                catch (Exception ex)<br />                {<br />                    return null;<br />                }<br />            }<br />            else<br />                return null;<br />        }

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 seja igual ao 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 adicionado foi wsseguro.

Consumir WebService

De 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)<br />        {<br />            wsseguro.WebService1 ws = new SoapTeste.wsseguro.WebService1();<br />            wsseguro.AuthenticationSoapHeader soap = new SoapTeste.wsseguro.AuthenticationSoapHeader();<br />            soap.DevToken = "123425";<br />            soap.User = "mauricio";<br />            soap.Pw = "mauricio";<br />            ws.AuthenticationSoapHeaderValue = soap;<br /><br />            Object obj = ws.AutenticarUsuario();<br />            if (obj == null)<br />            {<br />                Response.Write("Usuário não autorizado");<br />            }<br />            else<br />            {<br />                int numero = int.Parse(obj.ToString());<br />                Response.Write("Usuario autorizado -" + numero);<br />            }<br />        }

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. Daí 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.

Com mais de 20 anos trabalhando no mercado de tecnologia. Mestre em Engenharia Elétrica voltada para o mundo mobile, com mais de 20 livros publicados e cerca de 700 artigos publicados com intuito de ajudar àqueles que querem aprender a programar (site, software, desktop, serviços, api e mobile). Site pessoal: https://www.mauriciojunior.net - MVP, MCAD, MCP Microsoft

Ver perfil