TsgcWebSocketHTTPServer | Sessions

HTTP est un protocole sans état (du moins jusqu'à HTTP 1.1), donc le client demande un fichier, le serveur envoie une réponse et la connexion est fermée (vous pouvez activer le keep-alive pour que la connexion ne soit pas fermée immédiatement, mais c'est hors du cadre de cet article). Les sessions vous permettent de stocker des informations sur le client, qui peuvent être utilisées lors d'une connexion client par exemple. Vous pouvez utiliser n'importe quel identifiant de session unique, rechercher dans la liste des sessions si l'une d'elles existe déjà, et sinon, créer une nouvelle session. Une session peut être détruite après une période d'inactivité ou manuellement après la déconnexion du client.

 

Configuration

Il existe certaines propriétés dans TsgcWebSocketHTTPServer qui activent/désactivent les sessions dans le composant serveur. Les plus importantes sont :

 

Propriété Description
SessionState Til s'agit de la première propriété qui doit être activée pour utiliser les Sessions. Sans cette propriété activée, les sessions ne fonctionneront pas

SessionTimeout

Vous devez ici définir une valeur supérieure à zéro (en millisecondes) pour la durée maximale pendant laquelle une session sera active.
AutoStartSession Les sessions peuvent être créées automatiquement (AutoStartSession = true) ou manuellement (AutoStartSession = false). Si les sessions sont créées automatiquement, le serveur utilisera RemoteIP comme identifiant unique pour vérifier s'il existe une session active stockée.
SessionClass Facultatif. La classe que le serveur utilise lorsqu'il crée une nouvelle session. Affectez-lui votre propre descendant de TIdHTTPSession pour stocker vos propres données dans chaque session. Doit être définie avant l'activation du serveur.
SessionList La liste qui contient les sessions actives. Lisez-la pour rechercher, créer ou supprimer des sessions par code. Vous pouvez également affecter votre propre liste si vous avez besoin d'un contrôle total sur l'emplacement de stockage des sessions. Doit être affectée avant que le serveur soit activé.

 

 


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

 

Créer une session

Pour créer une nouvelle session, vous devez créer un nouvel identifiant de session qui soit unique. Vous pouvez utiliser n'importe quelle valeur. Exemple : si le client s'authentifie, vous pouvez utiliser utilisateur + mot de passe + ip distante comme identifiant de session.

Ensuite, recherchez dans la liste des sessions si elle existe déjà. Si elle n'existe pas, créez-en une nouvelle.

 

Lorsqu'une nouvelle session est créée, l'événement OnSessionStart est appelé et lorsque la session est fermée, l'événement OnSessionEnd est déclenché.

 


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;

Lire la session courante

Une fois qu'une session existe, le serveur l'attache à chaque requête qui porte le cookie de session. Lisez-la depuis ARequestInfo.Session, qui vaut nil lorsque la requête n'a pas de session.


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;

Utilisez votre propre classe de session

Si vous souhaitez conserver vos propres champs dans chaque session, au lieu d'utiliser la liste de chaînes Content, créez un descendant de TIdHTTPSession et dites au serveur de l'utiliser via la propriété SessionClass. Réglez-la avant que le serveur ne soit activé.

Le serveur continue de s'occuper de tout le reste : il génère l'identifiant de session unique, il envoie le cookie de session, il applique SessionTimeout et il supprime les sessions périmées. Redéfinissez le constructeur virtuel CreateInitialized si vous souhaitez initialiser vos propres champs à la création de la session.


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;

Utiliser votre propre liste de sessions

Si vous avez besoin d'un contrôle total sur la manière dont les sessions sont stockées, par exemple en les conservant dans une base de données ou en les partageant entre plusieurs serveurs, affectez votre propre liste à la propriété SessionList, avant que le serveur ne soit activé. Descendez de TIdHTTPDefaultSessionList et surchargez la méthode virtuelle CreateSession. Le serveur l'appelle en interne depuis CreateUniqueSession, de sorte que l'ID de session unique est toujours généré pour vous.

Lorsque vous affectez votre propre SessionList, la propriété SessionClass ne s'applique plus, car votre liste décide quelle classe créer.


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;

Une note à propos de OnCreateSession

L'événement OnCreateSession vous permet de renvoyer vous-même une instance de session, mais il ne lui assigne pas d'ID de session. Si vous créez la session avec un constructeur simple, l'ID de session et le cookie de session sont vides et la session ne peut plus jamais être retrouvée lors de la requête suivante. Utilisez plutôt SessionClass, qui est plus simple et gère tout cela pour vous.

De plus, n'appelez pas SessionList.CreateUniqueSession à l'intérieur de OnCreateSession. Cette méthode ajoute déjà la nouvelle session à la liste, et le serveur l'ajoute de nouveau lorsque votre gestionnaire se termine, de sorte que la même session se retrouve deux fois dans la liste.