Sessões usuário
The 4D web server provides built-in features for managing user sessions. Creating and maintaining user sessions allows you to control and improve the user experience on your web application. When user sessions are enabled, web clients can reuse the same server context from one request to another.
As sessões de usuário do servidor Web permitem:
- handle multiple requests simultaneously from the same web client through an unlimited number of preemptive processes (web server sessions are scalable),
- partilhar dados entre os processos de um cliente Web,
- associar privilégios a sessões de usuário,
- handle access through a
Session
object and the Session API.
Note: The current implementation is only the first step of an upcoming comprehensive feature allowing developers to manage hierarchical user permissions through sessions in the whole web application.
Activação de sessões
The session management feature can be enabled and disabled on your 4D web server. Existem diferentes formas de ativar a gestão de sessões:
- Using the Scalable sessions option on the "Web/Options (I)" page of the Settings (permanent setting):
Esta opção é selecionada por defeito nos novos projetos. It can however be disabled by selecting the No sessions option, in which case the web session features are disabled (no Session
object is available).
- Using the
.scalableSession
property of the Web Server object (to pass in the settings parameter of the.start()
function). In this case, this setting overrides the option defined in the Settings dialog box for the Web Server object (it is not stored on disk).
O comando
WEB SET OPTION
também pode definir o modo de sessão para o servidor Web principal.
In any cases, the setting is local to the machine; so it can be different on the 4D Server Web server and the Web servers of remote 4D machines.
Compatibility: A Legacy sessions option is available in projects created with a 4D version prior to 4D v18 R6 (for more information, please refer to the doc.4d.com web site).
Session implementation
When sessions are enabled, automatic mechanisms are implemented, based upon a private cookie set by 4D itself: "4DSID_AppName", where AppName is the name of the application project. Este cookie faz referência à sessão web atual da aplicação.
The cookie name can be get using the
.sessionCookieName
property.
-
In each web client request, the Web server checks for the presence and the value of the private "4DSID_AppName" cookie.
-
If the cookie has a value, 4D looks for the session that created this cookie among the existing sessions; if this session is found, it is reused for the call.
-
Se a solicitação do cliente não corresponder a uma sessão já aberta:
- a new session with a private "4DSID_AppName" cookie is created on the web server
- a new Guest
Session
object is created and is dedicated to the scalable web session.
The current Session
object can then be accessed through the Session
command in the code of any web processes.
Os processos Web geralmente não terminam, eles são reciclados em um pool para aumentar a eficiência. When a process finishes executing a request, it is put back in the pool and made available for the next request. Since a web process can be reused by any session, process variables must be cleared by your code at the end of its execution (using
CLEAR VARIABLE
for example). This cleanup is necessary for any process related information, such as a reference to an opened file. This is the reason why it is recommended to use the Session object when you want to keep session related information.
Partilhar informações
Each Session
object provides a .storage
property which is a shared object. This property allows you to share information between all processes handled by the session.
Duração da sessão
Uma sessão Web escalável é encerrada quando:
- o servidor web está parado,
- o tempo limite do cookie de sessão foi atingido.
The lifespan of an inactive cookie is 60 minutes by default, which means that the web server will automatically close inactive sessions after 60 minutes.
This timeout can be set using the .idleTimeout
property of the Session
object (the timeout cannot be less than 60 minutes).
When a scalable web session is closed, if the Session
command is called afterwards:
- the
Session
object does not contain privileges (it is a Guest session) - the
.storage
property is empty - um novo cookie de sessão é associado à sessão
Privilégios
Os privilégios podem ser associados a sessões. On the web server, you can provide specific access or features depending on the privileges of the session.
You can assign privileges usign the .setPrivileges()
function. In your code, you can check the session's privileges to allow or deny access using the .hasPrivilege()
function. By default, new sessions do not have any privilege: they are guest sessions (.isGuest()
function returns true).
In the current implementation (v18 R6), only the "WebAdmin" privilege is available.
Exemplo:
If (Session.hasPrivilege("WebAdmin"))
//Access is granted, do nothing
Else
//Display an authentication page
End if
Exemplo
Em uma aplicação CRM, cada vendedor gerencia seu próprio portefólio de clientes. The datastore contains at least two linked dataclasses: Customers and SalesPersons (a salesperson has several customers).
We want a salesperson to authenticate, open a session on the web server, and have the top 3 customers be loaded in the session.
- Executamos este URL para abrir uma sessão:
http://localhost:8044/authenticate.shtml
In a production environment, it it necessary to use a HTTPS connection to avoid any uncrypted information to circulate on the network.
- The
authenticate.shtml
page is a form containing userId et password input fields and sending a 4DACTION POST action:
<!DOCTYPE html>
<html>
<body bgcolor="#ffffff">
<FORM ACTION="/4DACTION/authenticate" METHOD=POST>
UserId: <INPUT TYPE=TEXT NAME=userId VALUE=""><br/>
Password: <INPUT TYPE=TEXT NAME=password VALUE=""><br/>
<INPUT TYPE=SUBMIT NAME=OK VALUE="Log In">
</FORM>
</body>
</html>
- The authenticate project method looks for the userID person and validates the password against the hashed value already stored in the SalesPersons table:
var $indexUserId; $indexPassword; $userId : Integer
var $password : Text
var $userTop3; $sales; $info : Object
ARRAY TEXT($anames; 0)
ARRAY TEXT($avalues; 0)
WEB GET VARIABLES($anames; $avalues)
$indexUserId:=Find in array($anames; "userId")
$userId:=Num($avalues{$indexUserId})
$indexPassword:=Find in array($anames; "password")
$password:=$avalues{$indexPassword}
$sales:=ds.SalesPersons.query("userId = :1"; $userId).first()
If ($sales#Null)
If (Verify password hash($password; $sales.password))
$info:=New object()
$info.userName:=$sales.firstname+" "+$sales.lastname
Session.setPrivileges($info)
Use (Session.storage)
If (Session.storage.myTop3=Null)
$userTop3:=$sales.customers.orderBy("totalPurchase desc").slice(0; 3)
Session.storage.myTop3:=$userTop3
End if
End use
WEB SEND HTTP REDIRECT("/authenticationOK.shtml")
Else
WEB SEND TEXT("This password is wrong")
End if
Else
WEB SEND TEXT("This userId is unknown")
End if