Atualmente, as aplicações Web tornaram-se parte integrante das nossas vidas, oferecendo funcionalidades convenientes que poupam tempo e simplificam as tarefas diárias. Por exemplo, a criação de contas em várias plataformas é uma das ações mais frequentes dos utilizadores nos sítios Web.
Os usuários esperam que este tipo de processo seja rápido e acessível, quer estejam em casa, a caminho de casa ou a relaxar na praia.
Por detrás desta simplicidade esconde-se uma realidade mais complexa. Estas operações requerem frequentemente a integração com sistemas de terceiros, tais como serviços de verificação de correio eletrônico. Isto introduz desafios relacionados com a segurança, a continuidade da experiência do utilizador e a proteção contra os ataques do tipo man-in-the-middle.
Para os desenvolvedores, garantir uma experiência suave significa gerenciar interações entre sistemas externos e a sessão web 4D. Isso envolve manter o contexto do usuário – recuperando dados, privilégios, e o passo exato de sua jornada para completar o processo.
Parece complicado? Não tem que ser! Descubra como construir aplicações web robustas que se comunicam de forma segura e eficiente com sistemas de terceiros com 4D 20R9.
Muitas vezes, em aplicações web, a experiência do usuário requer vários passos como:
Ao lidar com inventários de produtos num armazém:
- fazer uma seleção de produtos
- enviar a seleção para um sistema de registo externo
- voltar à lista de produtos na aplicação
ou
Ao criar uma conta num sítio Web:
- introduzir o e-mail e a palavra-passe para criar a conta
- validar o e-mail clicando numa ligação recebida num e-mail para finalizar a criação da conta
Esses passos requerem ir e voltar com sistemas de terceiros. Assim, uma sessão web 4D deve ser identificada de forma única no servidor para ser recuperada mais tarde.
A FUNÇÃO createOTP() NO OBJETO SESSION
O identificador de uma sessão web 4D é o cookie de sessão (“4DSID_AppName“). Trocar esse valor de cookie na rede entre uma aplicação web 4D e um sistema de terceiros é uma quebra de segurança desajeitada.
Para evitar isso, em qualquer processo web, um One-Time-Passcode(OTP) pode ser gerado graças à nova função createOTP() disponível no objeto Session.
Este OTP está ligado a esta sessão e permite a sua recuperação num pedido recebido, ao qual não é atribuído o cookie de sessão.
Este OTP só pode ser utilizado uma vez e pode ser associado a uma duração de vida.
exemplo
var $token : Text
$token:=Session.createOTP()
Como é que recupero uma sessão Web graças à OTP?
A sessão Web pode ser recuperada de duas formas.
o parâmetro $4DSID num URL
A sessão Web será recuperada automaticamente se o pedido recebido contiver no parâmetro $4DSID uma OTP válida correspondente à sessão.
exemplo
Neste exemplo, é criada uma conta de utilizador na classe de dados Users com a função create().
É recebido um objeto $info com o email + palavra-passe. É criado um novo utilizador e algumas informações são armazenadas na sessão, especialmente o passo atual do processo de criação da conta de utilizador(À espera do e-mail de validação) e o ID do utilizador.
É gerada uma OTP correspondente à sessão atual. Finalmente, é devolvido um URL com este OTP fornecido no parâmetro $4DSID.
// Na dataclass Users
Function create($info : Object) : Text
var $user : cs.UsersEntity
var $status : Object
var $token : Text
//Uma nova entidade da dataclasse Users é criada
$user:=This.new()
$user.fromObject($info)
$status:=$user.save()
Use (Session.storage)
Session.storage.status:=New shared object("step"; "Waiting for validation email"; "email"; $user.email; "ID"; $user.ID)
End use
$token:=Session.createOTP()
return "https://my4DApp/validateEmail?$4DSID="+$token
Posteriormente, esta URL é enviada ao utilizador como um link numa mensagem de correio eletrônico. O prefixo de URL /validateEmail é tratado pelos manipuladores de pedidos HTTP (arquivo HTTPHandlers.json).
[
{
"class": "RequestHandler",
"method": "validateEmail",
"regexPattern": "/validateEmail",
"verbs": "get"
}
]
Aqui está a função validateEmail() do RequestHandler singleton.
Function validateEmail() : 4D.OutgoingMessage
var $result:=4D.OutgoingMessage.new()
var $user : cs.UsersEntity
var $status : Object
If (Session.storage.status.step="Waiting for validation email")
$user:=ds.Users.get(Session.storage.status.ID)
$user.validated:=True
$status:=$user.save()
$result.setBody("Congratulations <br>"\
+"Your email "+Session.storage.status.email+" has been validated")
$result.setHeader("Content-Type"; "text/html")
Use (Session.storage.status)
Session.storage.status.step:="Email validated"
End use
Else
// Recupera a sessão com o OTP inválido
$result.setBody("Validation failed")
End if
return $result
Como o parâmetro $4DSID contém uma OTP válida correspondente à sessão original, o objeto Session refere-se à sessão que criou a OTP
Aqui está o resultado num browser:
A FUNÇÃO restore() NO OBJECTO SESSION
Normalmente, é aplicado um mecanismo de retorno de chamada quando estiver envolvido um sistema de terceiros. O princípio é o seguinte:
- enviar um pedido ao sistema de terceiros e passar uma URL de retorno de chamada
- depois de processar o pedido, o sistema externo chama a URL de retorno de chamada
Por vezes, os sistemas de terceiros não permitem que as URL de retorno de chamada contenham parâmetros personalizados como $4DSID.
No entanto, permitem que as informações do cliente (por exemplo, um estado) sejam enviadas e o sistema de terceiros devolve essas informações ao chamador. Esta é uma maneira de ser chamado de volta com uma sessão web 4D OTP.
Verifique a documentação da API do sistema de terceiros para encontrar o nome do parâmetro em questão. O exemplo abaixo usará o parâmetro state.
Uma função restore() está disponível no objeto Session e permite a recuperação da sessão correspondente a uma dada OTP.
No exemplo abaixo, a OTP é colocada no parâmetro reservado state em vez de ser adicionada na URL como um parâmetro $4DSID .
exemplo
Em uma aplicação web 4D, um empregado de armazém seleciona produtos para fazer um inventário e os envia a um sistema externo para registro. Aqui está a função sendProducts() chamada:
exposed Function sendProducts($chosenProducts : cs.ProductsSelection) : Text
var $token; $callBackURL; $callExternalAppURL; $result : Text
var $request : Object
//Os produtos escolhidos são colocados na sessão
Use (Session.storage)
Session.storage.info:=New shared object("inventoryStatus"; "Calling registring app")
Session.storage.chosenProducts:=$chosenProducts
End use
// $token é C318C81651F84F238EE72C14B46A45C3 (exemplo)
$token:=Session.createOTP()
//Construa a URL de callback - Colocar a OTP no parâmetro state
$callBackURL:="https://my4DApp/callBack?state="+$token
// Chama o sistema de registro externo - põe a URL de callback no parâmetro redirect
$callExternalAppURL:="https://acme.com/callRegistringApp?redirect="+$callBackURL
$requestObj:={method: HTTP POST method}
$request:=4D.HTTPRequest.new($callExternalAppURL; $requestObj).wait()
// O sistema de registro externo fez a callback. Esta call back recupera e atualiza a Sessão
// Agora o atributo inventoryStatus está atualizado
If (Position("Products registered"; Session.storage.info.inventoryStatus)#0)
$result:=Session.storage.info.inventoryStatus
Else
$result:="Registering failed"
End if
return $result
Os produtos escolhidos são colocados na sessão, e um OTP é gerado.
O sistema de terceiros é chamado. O parâmetro de redirecionamento indica o URL de retorno de chamada. Esta URL contém o parâmetro de estado, que é a OTP da sessão.
No exemplo acima, a URL do sistema de terceiros é:
https://acme.com/callRegistringApp?redirect=https://my4DApp/callBack?state=C318C81651F84F238EE72C14B46A45C3
O prefixo de URL /callBack é tratado pelos manipuladores de pedido HTTP (arquivo HTTPHandlers.json) na aplicação web 4D.
[
{
"class": "RequestHandler",
"method": "handleCallBack",
"regexPattern": "/callBack",
"verbs": "post"
}
]
Aqui está a função handleCallback() do RequestHandler singleton:
Function handleCallBack($request : 4D.IncomingMessage)
//Obtém o parâmetro state na URL
$otp:=$request.urlQuery.state
//Restaura a sessão graças ao OTP
$restore:=Session.restore($otp)
//Restauração bem-sucedida da sessão
If ($restore=True)
//Obtém o corpo da petição (informação enviada pelo sistema da terceira parte) - Contém "Products registered"
$text:=$request.getText()
//Atualiza a sessão com os resultados registrados
If ($text#Null)
Use (Session.storage.info)
Session.storage.info.inventoryStatus:=$text
If (Session.storage.chosenProducts#Null)
Session.storage.info.inventoryStatus+=" total price: "+String(Session.storage.chosenProducts.sum("price"))
End if
End use
End if
End if
Sobre o consumo de licença do Cliente 4D
Apenas a sessão original (que gera o OTP) consome uma licença 4D Client. Restaurar uma sessão (por exemplo, com um link de email de validação) não consome nenhuma licença 4D Client adicional.
Descarregue o HDI anexado para executar esses exemplos ao vivo e verifique a documentação para aprender mais.