Sessions para WebBroker

Esse artigo mostra algumas técnicas para criação de Sessions para aplicações baseadas em WebBroker em Delphi.

Salve, salve Delphianos!

Neste pequeno artigo demonstrarei algumas técnicas para criação de Sessions para aplicações baseadas em WebBroker.

Mas para que servem as Sessions? Uma resposta curta e grossa: serializar usuários em aplicações Web! Xiiiiiii Facunte, agora piorou, explique melhor!?

Vejamos dois exemplos:

e-Commerce

Serializamos clientes através de Sessions, onde todas as ações devem ser controladas, como adição de produtos no carrinho de compras, processo de identificação e pagamento.

Veja o esquema:

iBanking

Utilizada no processo de identificação do cliente, bem como em todas as ações realizadas durante a sessão (transferência entre contas, pagamentos, extrato, etc).

Mas chega de apresentações! Chegou a hora de por a mão na massa.

Listagem 1: Função randômica para criação de sessões

function NewIDRamdom:String; begin Result:= IntToHex(Random($ffffffff),8)+'-'+ IntToHex(Random($ffffffff),8)+'-'+                IntToHex(Random($ffffffff),8)+'-'+                IntToHex(Random($ffffffff),8); end;

Listagem 2: Função que utiliza diversos dados, como data e hora

function NewIDPlus:String;  var  iAno, iMes, iDia, iHora, iMinuto, iSegundo, iMSegundo: Word;  begin     DecodeDate(Now, iAno, iMes, iDia);     DecodeTime(Now, iHor, iMin, iSeg, iMSeg);     Result:= IntToHex(iAno,3)+'-'+                 IntToHex(iMes,2)+'-'+                 IntToHex(iDia,2)+'-'+                 IntToHex(iMSegundo,3)+'-'+                 IntToHex(iSegundo,2)+'-'+                 IntToHex(iMinuto,2)+'-'+                 IntToHex(iHora,2);  end;

Listagem 3: Função que retorna uma GUID

function NewIdGuid:String; var      MinhaGUID:TGUID; begin      CoCreateGuid(MinhaGuid);      Result:=GUIDToString(MinhaGuid); end;

Nesse exemplo, necessitamos de duas units: ActiveX e COMOBJ.

 Exemplos de utilização:

Variável de sessão:

var  IDSession: String;

Variável Internet, que identifica o usuário:

<input type=”hidden” name=”ID” value=”...>  http://servidor/aplicacao.dll/login?ID=....

No evento OnBeforeDispatch insira o código que segue:

begin   if Request.ContentFields.values[‘ID’]=’’ then      IDSession := NewIdGuid; end;

 E no parser do seu Producer (onHTMLTag), coloque o código que segue:

begin     if TagString=’ID’ then       ReplaceText:=IDSession; end;

 Em todas as páginas você deverá inserir a Tag transparente <#ID>, exemplo:

<input type=”hidden” name=”ID” value=”<#ID>”>  http://servidor/aplicacao.dll/login?ID=<#ID>  <form name=”cliente” action=”/apl.dll/confirma?ID=<#ID>”>

A seguir demonstrarei como criar e administrar sessions para o saudoso WebBroker. Crie uma nova aplicação baseada na tecnologia WebBroker, através das opções File/New.../WebServer Application. Selecione qualquer uma das opções (CGI, ISAPI, Apache...). Salve o projeto com o nome Sessoes.DPR e a unit como un_sessoes.pas. Com o objetivo de criar um projeto profissional, estaremos utilizando um banco de dados para armazenar informações sobre as sessions.

 

Veja a estrutura das tabelas:

Tabela de Sessão
Campo Tipo
SSS_ID Varchar PK
SSS_USU_Id Int
SSS_DataHoraUltAtualizacao DateTime
SSS_IP Varchar
 
Tabela Usuário
Campo Tipo
USU_ID Int PK
USU_Nome Varchar
USU_Senha Varchar

A estrutura modelo é baseada em SQL Server, mas você poderá adaptar facilmente em qualquer SGDB. Em nosso projeto utilizaremos ADO, mas você poderá utilizar a tecnologia dbExpress, ou até mesmo o BDE. Prosseguindo com o projeto, insira os seguintes objetos.

AdoConnection
Name dbconexao
LoginPrompt False
ConnectionString Faça a conexão com a sua base de dados.
AdoDataSet
Name QrySessao
Connection dbConexao

Neste ponto implementaremos as rotinas comuns para o tratamento de sessions. Na seção public, declare a função NewIdGuid  (responsável pela criação de um novo ID), e faça a implementação como segue:

function NewIdGuid:String; var      MinhaGUID:TGUID;      sIDInterno:String; begin      CoCreateGuid(MinhaGuid);      sIDInterno:= GUIDToString(MinhaGuid);      // Adiciona a sessão no banco de dados      dbConexao.Execute(‘Insert into Sessao values(‘+         QuotedStr(sIDInterno)+’,’+         ‘0,’+         QuotedStr(DateTimetoStr(Now))+’,’+         QuotedStr(Request.RemoteAddr)+’)’,                cmdText, [eoExecuteNoRecords]);          Result:= sIDInterno; end;

Vamos analisar o código:

 

Criamos  uma chave única (ID)  e setamos para sIDInterno.      CoCreateGuid(MinhaGuid);

sIDInterno:= GUIDToString(MinhaGuid);

Inserimos o novo ID no banco de dados, e transmitimos os seguintes parâmetros:

     dbConexao.Execute(‘Insert into Sessao values(‘+  novo ID,      QuotedStr(sIDInterno)+’,’+  

Usuário = 0. Isso indica que ainda não efetuou login.    

‘0,’+  

Data e Hora Atual.

QuotedStr(DateTimetoStr(Now))+’,’+

E o IP do usuário.

      QuotedStr(Request.RemoteAddr)+’)’,         

Com isso apenas adicionamos a chave no banco de dados. Na cláusula uses, acrescente as units ComObj e ActiveX.

Na seção protected,  declare a seguinte variável:

protected      sID: String;

A variável sID será responsável pelo controle do session ID. Neste ponto criaremos a função que irá checar a existência de um ID e retornar o valor do mesmo.

function ChecaId:String; var    sIDinterno:string; begin      // verifica se existe ID (post)      sIDInterno:=Request.ContentFields.Values[‘ID’];      if sIDInterno=’’  then      begin           // verifica se existe ID (get)           sIDInterno:=Request.QueryFields.Values[‘ID’];           if sIDInterno=’’ then           begin               // não existe ID, cria um novo;              sIDInterno:=NewIdGuid;           end;      end;      // Retorna ID      Result:=sIDInterno; end;  

Vamos analisar a lógica da função:

Neste ponto verificamos a existência do campo ID num FORM com método POST.

// verifica se existe ID (post) sIDInterno:=Request.ContentFields.Values[‘ID’]; if sIDInterno=’’  then begin

Em caso negativo, verifica-se a existência do campo ID num método GET, e se persistir, criamos um novo ID.

Este é ponto mais importante da sua aplicação. Necessitamos transmitir o campo ID em todas as ações, seja dentro de um form ou através de uma URL, exemplos:

    1. http://servidor/aplicacao.dll?ID=<#ID> 2. <form method=post action=”aplicação.dll”>    <input type=hidden name=”ID” value=”<#ID>”>

Repare que em ambos os casos utilizamos a tag transparente <#ID>. Com isso deveremos realizar o parser em todos os objetos  Producers através do evento OnHtmlTag;

Amigos, em todos os producers (normalmente centralizo minhas aplicações num único Producer), vocês deverão realizar o parser. Veja o exemplo:

Evento OnHtmlTag.

If TagString=’ID’ then begin   ReplaceText:=ChecaId; end;  

Neste ponto criaremos as funções para efetuar LogIn e LogOut além de uma função que verifica se o usuário está logado no sistema. Como exemplo, crie um HTML com os campos: usuario e senha:

  <html> <body> <form method=”post” action=”login”>     <input type=”HIDDEN” name=”ID” value=”<#ID>”     Usuario <input type=TEXT name=usuario><BR>     Senha <input type=password name=senha><BR>     <input type=submit value=”confirma”> </form> </body> </html>  

A função Login retorna uma expressão lógica com o resultado da operação.

  function Login:boolean; var    sUsuario, sSenha, sURL:string; begin   sID:=ChecaId;   sUsuario:=Request.ContentFields.Values[‘usuario’];   sSenha:=Request.ContentFields.Values[‘senha’];   with QrySessao do   begin    Close;    CommandText:=’Select usu_id, usu_nome, usu_senha from usuario whereUSU_NOME=’+QuotedStr(sUsuario);    Open;    If Empty or FieldByName(‘usu_senha’).AsString<>sSenha then    begin      Result:=False;    end    Else    begin      // Atualiza       dbConexao.Execute(‘UpDate Sessao set ‘+          ‘SSS_Usu_id=’+FieldByName(‘usu_id’).AsString+’, ‘+    ‘SSS_DataUltAtualizacao=’+QuotedStr(DateTimetoStr(Now))+     ‘,’+ QuotedStr(Request.RemoteAddr)+’)’,           cmdText, [eoExecuteNoRecords]);               Result:=True;    End;    Close;    end;    end;  

A função Login, verifica a existência do usuário e a validade da senha. Em caso positivo, a tabela Sessao é atualizada com os dados do usuário(ID, Código do Usuário e Data/Hora atualização). Com isso autenticamos o usuário em nossa base.Além disso utilizamos a variável sURL que contém a URL de destino após o usuário efetuar o Login no sistema. Exemplo:

- Usuário tenta acessar uma área restrita

 

Função LogOut

A função LogOut retira o vínculo do usuário na tabela Sessão. Devemos passar o parâmetro ID para que a operação seja realizadda.

function Logout(ID:String):boolean; begin     try        dbConexao.Execute(‘Update Sessao set SSS_Usu_id=0 where SSS_ID = ‘+ID,cmdText,        [eoExecuteNoRecords]);            Result:=True;                 except             Result:=False;        end; end;

Função VerificaLogin

Esta função verifica se o usuário está logado no sistema através da autenticação e do tempo. Estou prevendo 1 dia, mas você poderá configurar de acordo com a sua necessidade (1 hora, 30 minutos, 10 minutos, etc).

function VerificaLogin(ID):boolean; begin   with QrySessao do   begin    Close;    CommandText:=’select SSS_USU_ID, SSS_DataHoraUltAtualizacao from Sessao where SSS_ID=’+ID;    Open;    If (Empty) or       (FieldByName(‘SSS_USU_ID’).AsInteger=0) or       (FieldByName(‘SSS_DataHoraUltAtualizacao’).Value<Now-1     then      Result:=False     Else      Result:=True;   end; end;

Utilizando as funções

Em todas as ações que necessitam de Login, você deverá inserir o código abaixo:

  if not(VerificaLogin(sID)) then begin   // coloque aqui o código que chama a sua tela de LOGIN   // exemplo:   Response.Content:=’’; end;  

Sugiro a criação de uma rotina de expurgo para eliminar todos os registros da tabela Sessao com atualização inferior a 2 dias.

Espero que tenham compreendido o artigo e que possam aproveitá-lo em seus sistemas.

 

Forte abraço.

Ebook exclusivo
Dê um upgrade no início da sua jornada. Crie sua conta grátis e baixe o e-book

Artigos relacionados