TsgcWebSocketHTTPServer | Sessies

HTTP is een staatloos protocol (in ieder geval tot en met HTTP 1.1), dus de client vraagt een bestand op, de server stuurt een respons en de verbinding wordt gesloten (u kunt keep-alive inschakelen zodat de verbinding niet onmiddellijk wordt gesloten, maar dat valt buiten het bestek van dit artikel). Sessies stellen u in staat informatie over de client op te slaan, die bijvoorbeeld kan worden gebruikt bij het inloggen van een client. U kunt een willekeurige unieke sessie-ID gebruiken, de lijst met sessies doorzoeken om te zien of er al een bestaat, en zo niet een nieuwe sessie aanmaken. Een sessie kan worden vernietigd na een periode van inactiviteit of handmatig na het uitloggen van de client.

 

Configuratie

Er zijn enkele eigenschappen in TsgcWebSocketHTTPServer die sessies in het servercomponent in- of uitschakelen. De belangrijkste zijn:

 

Eigenschap Beschrijving
SessionState Dit is de eerste eigenschap die moet worden ingeschakeld om sessies te kunnen gebruiken. Zonder dat deze eigenschap is ingeschakeld, werken sessies niet

SessionTimeout

Hier moet u een waarde groter dan nul instellen (in milliseconden) voor de maximale tijd dat een sessie actief zal zijn.
AutoStartSession Sessies kunnen automatisch worden aangemaakt (AutoStartSession = true) of handmatig (AutoStartSession = false). Als sessies automatisch worden aangemaakt, gebruikt de server RemoteIP als unieke identificator om te controleren of er een actieve sessie is opgeslagen.
SessionClass Optioneel. De klasse die de server gebruikt wanneer hij een nieuwe sessie maakt. Stel deze in op uw eigen TIdHTTPSession-afstammeling om uw eigen gegevens in elke sessie op te slaan. Moet worden ingesteld voordat de server wordt geactiveerd.
SessionList De lijst met de actieve sessies. Lees hem om sessies via code te zoeken, aan te maken of te verwijderen. U kunt ook uw eigen lijst toewijzen als u volledige controle nodig hebt over waar sessies worden opgeslagen. Moet worden toegewezen voordat de server wordt geactiveerd.

 

 


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

 

Sessie aanmaken

Om een nieuwe sessie te maken, moet u een nieuwe sessie-ID aanmaken die uniek is. U kunt elke gewenste waarde gebruiken. Voorbeeld: als de client zich authenticeert, kunt u gebruikersnaam + wachtwoord + extern IP-adres als sessie-ID gebruiken.

Zoek vervolgens in de sessielijst om te controleren of deze al bestaat. Als deze niet bestaat, maakt u een nieuwe aan.

 

Wanneer een nieuwe sessie wordt aangemaakt, wordt de gebeurtenis OnSessionStart aangeroepen en wanneer de sessie wordt gesloten, wordt de gebeurtenis OnSessionEnd geactiveerd.

 


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;

De huidige sessie lezen

Zodra een sessie bestaat, koppelt de server deze aan elk verzoek dat de sessiecookie draagt. Lees deze uit ARequestInfo.Session, die nil is wanneer het verzoek geen sessie heeft.


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;

Uw eigen sessieklasse gebruiken

Als u uw eigen velden in elke sessie wilt bewaren, in plaats van de Content-stringlijst te gebruiken, maak dan een afstammeling van TIdHTTPSession en laat de server die gebruiken via de eigenschap SessionClass. Stel deze in voordat de server wordt geactiveerd.

De server blijft voor al het overige zorgen: hij genereert het unieke sessie-ID, verstuurt de sessiecookie, past SessionTimeout toe en verwijdert verlopen sessies. Overschrijf de virtuele constructor CreateInitialized als u eigen velden wilt initialiseren wanneer de sessie wordt aangemaakt.


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;

Uw eigen sessielijst gebruiken

Als u volledige controle nodig heeft over hoe sessies worden opgeslagen, bijvoorbeeld door ze in een database te bewaren of tussen meerdere servers te delen, wijs dan vóór activering van de server uw eigen lijst toe aan de eigenschap SessionList. Erf over van TIdHTTPDefaultSessionList en override de virtuele methode CreateSession. De server roept deze intern aan vanuit CreateUniqueSession, zodat de unieke sessie-ID nog steeds voor u wordt gegenereerd.

Wanneer u uw eigen SessionList toewijst, is de eigenschap SessionClass niet langer van toepassing, omdat uw lijst bepaalt welke klasse wordt aangemaakt.


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;

Een opmerking over OnCreateSession

Met de gebeurtenis OnCreateSession kunt u zelf een sessie-instantie teruggeven, maar er wordt geen sessie-ID aan toegekend. Als u de sessie met een gewone constructor maakt, zijn de sessie-ID en de sessiecookie leeg en kan de sessie bij het volgende verzoek nooit meer worden teruggevonden. Gebruik in plaats daarvan SessionClass, dat eenvoudiger is en dat allemaal voor u afhandelt.

Roep ook SessionList.CreateUniqueSession niet aan binnen OnCreateSession. Die methode voegt de nieuwe sessie al toe aan de lijst, en de server voegt deze opnieuw toe wanneer uw handler terugkeert, zodat dezelfde sessie tweemaal in de lijst terechtkomt.