Sessions para WebBroker

Você precisa estar logado para dar um feedback. Clique aqui para efetuar o login
Para efetuar o download você precisa estar logado. Clique aqui para efetuar o login
Confirmar voto
0
 (0)  (0)

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:

  • Internauta entra na loja virtual e recebe uma sessão única: A01-FF1;
  • Internauta escolhe produto e coloca na sua cesta. Sua cesta possui a mesma identificação da sessão: A01-FF1;
  • Internauta entra na área de identificação e o sistema vincula seu cadastro à sessão: A01-FF1;
  • Internauta finaliza processo de compra, e o sistema identifica suas opções através da sessão: A01-FF1.

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).

  • Cliente entra no site do banco e recebe uma sessão única: BBC-AAX;
  • Cliente informa dados de sua conta e realiza login do iBanking. O sistema vincula a conta logada na sessão BBC-AAX. Para maior segurança, além de um servidor seguro, a sessão criada possui algumas informações do internauta, como por exemplo, o número do IP (obviamente criptografado);
  • Cliente realiza todas as transações de maneira segura, onde o sistema sempre verifica as informações da sessão BBC-AAX, e da máquina do usuário;
  • Cliente finaliza processo, e o sistema libera a sessão BBC-AAX.

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

 
Você precisa estar logado para dar um feedback. Clique aqui para efetuar o login
Ficou com alguma dúvida?