Desenvolvimento - Web Services

WebServices usando soapHeader

Neste artigo gostaria de mostrar como criar um webservices seguro, ou seja, utilizando token, usuário, senha e soapHeader.

por Mauricio Junior



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.

Mauricio Junior

Mauricio Junior - Formado pela Faculdade Anhanguera, Especialista pela FGV (Fundação Getúlio Vargas), Pós-Graduação em Docência Superior e cursando Mestrado na UNB Engenharia Elétrica; . Tenho 29 anos e possuo sete livros publicados pela editora Ciência Moderna e sou editor do Linha de Código.
Sou Certificado Microsoft MCP, MCAD e MVP, faço parte da comunidade ASPNETI.COM, onde publico artigos, vídeos, ebooks e livros Publico artigos, vídeos e podcast em outras comunidades. Trabalho como Analista de Sistemas / Desenvolvedor na empresa ATP S/A.
Blog:
blog.mauriciojunior.org
Site pessoal: www.mauriciojunior.org