TsgcWebSocketHTTPServer | Sesiones

HTTP es un protocolo sin estado (al menos hasta HTTP 1.1), de modo que el cliente solicita un archivo, el servidor envía una respuesta y la conexión se cierra (puede habilitar keep-alive para que la conexión no se cierre inmediatamente, pero eso está fuera del ámbito de este artículo). Las sesiones permiten almacenar información sobre el cliente, que puede usarse durante el inicio de sesión de un cliente, por ejemplo. Puede usar cualquier id de sesión único, buscar en la lista de sesiones si ya existe una y, si no, crear una nueva sesión. Una sesión puede destruirse tras un período de inactividad o manualmente tras el cierre de sesión del cliente.

 

Configuración

Hay algunas propiedades en TsgcWebSocketHTTPServer que habilitan/deshabilitan las sesiones en el componente servidor. Las más importantes son:

 

Propiedad Descripción
SessionState Esta es la primera propiedad que debe habilitarse para usar las sesiones. Sin esta propiedad habilitada, las sesiones no funcionarán

SessionTimeout

Aquí debe establecer un valor mayor que cero (en milisegundos) para el tiempo máximo que una sesión estará activa.
AutoStartSession Las sesiones pueden crearse automáticamente (AutoStartSession = true) o manualmente (AutoStartSession = false). Si las sesiones se crean automáticamente, el servidor utilizará RemoteIP como identificador único para comprobar si existe una sesión activa almacenada.
SessionClass Opcional. La clase que usa el servidor cuando crea una nueva sesión. Asígnele su propio descendiente de TIdHTTPSession para almacenar sus propios datos dentro de cada sesión. Debe establecerse antes de que el servidor se active.
SessionList La lista que contiene las sesiones activas. Léala para buscar, crear o eliminar sesiones por código. También puede asignar su propia lista si necesita un control total sobre dónde se guardan las sesiones. Debe asignarse antes de activar el servidor.

 

 


TsgcWebSocketHTTPServer1.SessionState := True;
TsgcWebSocketHTTPServer1.SessionTimeout := 600000;
TsgcWebSocketHTTPServer1.AutoStartSession := False;

 

Crear Sesión

Para crear una nueva sesión, debe crear un nuevo ID de sesión que sea único. Puede utilizar cualquier valor. Ejemplo: si el cliente se está autenticando, puede usar usuario + contraseña + IP remota como ID de sesión.

A continuación, busque en la lista de sesiones para comprobar si ya existe. Si no existe, cree una nueva.

 

Cuando se crea una nueva sesión, se llama al evento OnSessionStart y, cuando la sesión se cierra, se lanza el evento OnSessionEnd.

 


procedure OnCommandGet(AContext: TIdContext; ARequestInfo: TIdHTTPRequestInfo; 
  AResponseInfo: TIdHTTPResponseInfo);
var
  vID: String;
  oSession: TIdHTTPSession;
begin
  if ARequestInfo.Document = '/' then
    AResponseInfo.ServeFile(AContext, 'yourpathhere\index.html')
  else
  begin
    // check if user is valid
    if not ((ARequestInfo.AuthUsername = 'user') and (ARequestInfo.AuthPassword = 'pass')) then
      AResponseInfo.AuthRealm := 'Authenticate'
    else
    begin
      // create a new session id with authentication data
      vID := ARequestInfo.AuthUsername + '_' + ARequestInfo.AuthPassword + '_' + ARequestInfo.RemoteIP;
 
      // search session
      oSession := TsgcWebSocketHTTPServer1.SessionList.GetSession(vID, ARequestInfo.RemoteIP);
 
      // create new session if not exists
      if not Assigned(oSession) then
        oSession := TsgcWebSocketHTTPServer1.SessionList.CreateSession(ARequestInfo.RemoteIP, vID);
 
      AResponseInfo.ContentText := '<html><head></head><body>Authenticated</body></html>';
      AResponseInfo.ResponseNo := 200;
    end;
  end;
end;

Leer la sesión actual

Una vez que existe una sesión, el servidor la adjunta a cada petición que lleve la cookie de sesión. Léala desde ARequestInfo.Session, que es nil cuando la petición no tiene sesión.


procedure OnCommandGet(AContext: TIdContext; ARequestInfo: TIdHTTPRequestInfo;
  AResponseInfo: TIdHTTPResponseInfo);
begin
  if Assigned(ARequestInfo.Session) then
  begin
    // Content is a TStrings you can use to store your own values
    ARequestInfo.Session.Content.Values['visits'] :=
      IntToStr(StrToIntDef(ARequestInfo.Session.Content.Values['visits'], 0) + 1);

    AResponseInfo.ContentText := 'Session ' + ARequestInfo.Session.SessionID +
      ' visits: ' + ARequestInfo.Session.Content.Values['visits'];
  end
  else
    AResponseInfo.ContentText := 'No session';
end;

Usar su propia clase de sesión

Si desea guardar sus propios campos dentro de cada sesión, en lugar de usar la lista de cadenas Content, cree un descendiente de TIdHTTPSession e indique al servidor que lo use mediante la propiedad SessionClass. Establézcala antes de que el servidor se active.

El servidor sigue ocupándose de todo lo demás: genera el ID de sesión único, envía la cookie de sesión, aplica SessionTimeout y elimina las sesiones caducadas. Sobrescriba el constructor virtual CreateInitialized si desea inicializar sus propios campos cuando se crea la sesión.


type
  TMySession = class(TIdHTTPSession)
  private
    FUserName: String;
    FLoginTime: TDateTime;
  public
    constructor CreateInitialized(AOwner: TIdHTTPCustomSessionList;
      const SessionID, RemoteIP: string); override;
    property UserName: String read FUserName write FUserName;
    property LoginTime: TDateTime read FLoginTime write FLoginTime;
  end;

constructor TMySession.CreateInitialized(AOwner: TIdHTTPCustomSessionList;
  const SessionID, RemoteIP: string);
begin
  inherited CreateInitialized(AOwner, SessionID, RemoteIP);
  FLoginTime := Now;
end;

// configure the server before it starts
TsgcWebSocketHTTPServer1.SessionState := True;
TsgcWebSocketHTTPServer1.SessionTimeout := 600000;
TsgcWebSocketHTTPServer1.SessionClass := TMySession;
TsgcWebSocketHTTPServer1.Active := True;

// and read it back in any request
procedure OnCommandGet(AContext: TIdContext; ARequestInfo: TIdHTTPRequestInfo;
  AResponseInfo: TIdHTTPResponseInfo);
begin
  if ARequestInfo.Session is TMySession then
    AResponseInfo.ContentText := TMySession(ARequestInfo.Session).UserName;
end;

Utilice su propia lista de sesiones

Si necesita control total sobre cómo se almacenan las sesiones, por ejemplo guardándolas en una base de datos o compartiéndolas entre varios servidores, asigne su propia lista a la propiedad SessionList antes de activar el servidor. Derive de TIdHTTPDefaultSessionList y sobrescriba el método virtual CreateSession. El servidor lo llama internamente desde CreateUniqueSession, por lo que el ID único de sesión se sigue generando por usted.

Cuando asigna su propia SessionList, la propiedad SessionClass ya no se aplica, porque su lista decide qué clase crear.


type
  TMySessionList = class(TIdHTTPDefaultSessionList)
  public
    function CreateSession(const RemoteIP, SessionID: string)
      : TIdHTTPSession; override;
  end;

function TMySessionList.CreateSession(const RemoteIP, SessionID: string)
  : TIdHTTPSession;
begin
  Result := TMySession.CreateInitialized(Self, SessionID, RemoteIP);
  SessionList.Add(Result);
end;

// assign it before the server starts
TsgcWebSocketHTTPServer1.SessionList := TMySessionList.Create(nil);
TsgcWebSocketHTTPServer1.Active := True;

Una nota sobre OnCreateSession

El evento OnCreateSession le permite devolver usted mismo una instancia de sesión, pero no le asigna un ID de sesión. Si crea la sesión con un constructor simple, el ID de sesión y la cookie de sesión quedan vacíos y la sesión nunca podrá volver a encontrarse en la siguiente petición. Use SessionClass en su lugar, que es más sencillo y se encarga de todo eso por usted.

Además, no llame a SessionList.CreateUniqueSession dentro de OnCreateSession. Ese método ya añade la nueva sesión a la lista, y el servidor la añade de nuevo cuando su manejador retorna, por lo que la misma sesión acaba dos veces en la lista.