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.