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:
- 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 <#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.
Artigos relacionados
-
Artigo
-
Artigo
-
Artigo
-
Artigo
-
Artigo