SessionHandler erweitern

  • Betroffene App
    WoltLab Suite Core

    Hallo zusammen,

    Habe da eine kleine Problematik, wo ich eventuell eine kleine Hilfe brauchen könnte.

    Und zwar möchte ich das Forum in Symfony 3.3 einbinden.

    Design-Technisch ist das schon erledigt, dinge wie PN/Profil usw was vom Forum geliefert wird habe ich deaktiviert.

    Das habe ich zum Teil durch ein eigenes Plugin erledigt. Habe es Redirect-Plugin genannt, was auf events reagiert.

    Wird das Profil aufgerufen wird die ID umgelenkt zu Symfony.

    Was mich jetzt noch stört, sind die "Hardcoded" Änderungen in den php-Dateien die ich gerne durch ein Plugin ersetzen würde.

    Und zwar habe ich in der SessionHandler.class.php am ende der load-funktion:

    Code
    public function load($sessionEditorClassName, $sessionID) {

    Eine weiter funktion aufgerufen:

    Code
    $this->checkSymfonyUser();

    Diese funktion ruft Symfony auf und ließt dort die Session des Users aus. In dieser Session steht eine wcfUserID drin. Anhand dieser ID lade ich dann das User-Object:

    Code
    $newUser = new User($symfonyInstance->getUser()->getWcfUserId());

    Letzendlich setze ich diesen User in die WCF-Session:

    Code
    $this->changeUser($newUser);

    Es geht also letzendlich einfach um eine möglichkeit, die load-funktion per Plugin zu ergänzen.

    Gibt es diese Möglichkeit, oder wie könnte man sowas realisieren?

    Wenn es zu komplex wird muss halt dieser Teil hardcoded bleiben, aber mir wäre ein Plugin lieber.

    Wäre dankbar um jeglichen Tipp!

    Danke !!

    • Offizieller Beitrag

    Wenn ich Dein Anliegen richtig verstanden habe, sollte folgendes als Plugin funktionieren:

    1. Erstelle eine eigene Klasse SymfonyUserAuthentication, die IUserAuthentication implementiert, indem sie AbstractUserAuthentication oder DefaultUserAuthentication erweitert. In der Klasse müsstest Du dann wahrscheinlich die Methode loginAutomatically() überschreiben. Diese Methode wird von SessionHandler::create() aufgerufen, wobei diese Methode wiederum am Ende der von Dir erwähnten Methode SessionHandler::load() aufgerufen wird.
    2. Setze einen Event-Listener auf init@wcf\system\user\authentication\UserAuthenticationFactory und ersetze mit dem Event-Listener UserAuthenticationFactory::$className durch Deine Symfony-Authentifizierungsklasse.
  • Hallo,

    Vielen Dank für die Ausführliche Antwort. Über die Funktion loginAutomatically() zu gehen hatte ich zuvor mal getestet, indem ich dort hardcoded auf die Session von Symfony zurückgreife.

    Dies hat bei mir jedoch ein Problem offen gelassen.

    Wenn der User (als Gast) das Forum betritt, erhält er vom WCF eine Gast-Session-ID. Wenn er sich jetzt erst einloggt und von Symfony eine User-Session erhält, ist man im Forum weiterhin als Gast unterwegs, da die Funktion loginAutomatically() nur bei SessionHandler::load aufgerufen wird wenn es noch keine Session für diesen user gibt.

    Wenn der User eine WCF-Session hat, wird nur getExistingSession() aufgerufen. Die Funktion SessionHandler::create() wird übersprungen, da die Bedingung $this->session === null nicht wahr ist.

    Selbige Problematik zeigt sich, wenn der User auf "Logout" klickt und in Symfony abgemeldet wird. Ich müsste dann im Symfony Logout-Event noch eine Verknüpfung zu WCF herstellen, der die Löschung der Session anstößt.

    Nächste Problematik ist, wenn der User sich ausloggt und in einen anderen Account einloggt. (Ist zwar nicht zulässig, aber gibt es dennoch häufig). Das WCF bekommt diesen User-Wechsel nicht mit.

    Hättest du da noch eine Idee zu? Wie ich das lösen könnte? Möchte ungern überall Verknüpfungen rein bringen, da die Verbindung zweier Skripte, dieses Umfanges doch Probleme machen können.

    Danke !!

    • Offizieller Beitrag

    Ich selbst habe mich bisher noch nicht intensiv mit der Benutzer-Authentifizierung beschäftigt, kann Dir daher bei solchen Details nicht weiterhelfen.

    Da es sich aber so anhört, dass die Logins sehr verzahnt sein sollen, erscheint es mir logisch, dass Du dann auch entsprechende Verknüpfungen hinzufügen musst, damit sich die beiden Systeme gegenseitig über Logins und Logouts informieren können.

  • Hallo,

    Ja die Verknüpfungen sind die eine Möglichkeit. Sprich dass ich im WCF bei Login/Logout über Events Informationen dazu an Symfony sende.

    Dasselbe in umgekehrter Reihenfolge. Symfony sendet ebenfalls Informationen an das WCF.

    Das bedeutet jedoch, dass ich 4! Verknüpfungen benötige, auf die ich gerne Verzichten möchte.

    Das erreiche ich wie beschrieben, indem ich im SessionHandler in der load() Funktion ganz am Ende die Session Abfrage und dem WCF zur Verfügung stelle. Somit habe ich nur 1 Verknüpfung.

    Die Registrierung und der Login im WCF sind sowieso deaktiviert und leiten auf Symfony weiter. Sämtliche Links im WCF diesbezüglich wurden durch Events bearbeitet.

    Das bedeutet, dass Symfony die einzige Authentifizierung im kompletten System ist.

    Das funktioniert so auch Tadellos. Im load() eine Funktion aufrufen wie oben beschrieben und es klappt zu 100%.

    Nur ist dies hardcoded und könnte bei Updates Probleme machen.

    Deshalb die Anfrage wie das als Plugin möglich wäre.

    Danke!!

    • Offizieller Beitrag

    Event-Listener auf beforeInit von wcf\system\session\SessionFactory und dort dann den folgenden Code ausführen.

    PHP
    $user = new \wcf\data\user\User($userIDdieIrgendwoHerKommt);
    \wcf\system\session\SessionHandler::getInstance()->changeUser($user);

    Der obige Code stellt natürlich nur das innere Fragment dar, die Interaktion mit Symfony fehlt hier, genauso wie das "durm herum" eines Event-Listeners. Siehe dazu auch die Einführung in Event-Listenern, insbesondere ab dem Abschnitt Listening to Events.

  • Hallo,

    Wow okay. Das muss man erstmal so verfolgt bekommen wie es tatsächlich ist.

    Auf SessionFactory::beforeInit zu gehen klappt theoretisch, weil das beforeInit umgehend gefeuert wird, nachdem SessionHandler::load() aufgerufen wird.

    Wir haben jetzt das WCF2.1 gelöscht und auf die neueste Core aktualisiert. Dabei fällt mir ein Problem auf.

    Die Funktion SessionHandler::changeUser() hat sich eurerseits geändert. Und zwar wird dort folgender Aufruf gemacht:

    WCF::setLanguage($this->languageID ?: 0);

    Dies führt zu einer exception, weil das Language-System erst nach der Session initialisiert wird.

    Sprich der eventListener hätte in WCF2.1 noch funktioniert. In der neuesten Core Version jedoch leider nicht mehr.

    Gibt es denn noch eine Möglichkeit?

    Danke!

  • Der Fehler:

    Code
    Fatal error: Call to a member function setLanguageID() on null in /var/www/vhosts/x.com/forum.x.com/core/lib/system/WCF.class.php on line 696

    Das liegt daran, dass in der SessionHandler::changeUser() folgendes ausgeführt wird:

    Code
    WCF::setLanguage($this->languageID ?: 0);

    Das LanguageSystem aber zu dem Zeitpunkt SessionFactory::beforeInit noch nicht initialisiert ist. Da in der WCF-Klasse erst Session und dann Language initialisiert wird.

    In der WCF2.1 gab es diesen Aufruf nicht und es war auch deutlich mehr Quellcode in der SessionHandler::changeUser()

    Edit: Habe das jetzt als Plugin umgesetzt, sodass auf ein Event reagiert wird:

    XML
    <?xml version="1.0" encoding="UTF-8"?>
    <data xmlns="http://www.woltlab.com" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.woltlab.com http://www.woltlab.com/XSD/maelstrom/eventListener.xsd">
        <import>
            <eventlistener name="symfonyAuthListener">
                <eventclassname>wcf\system\session\SessionFactory</eventclassname>
                <eventname>beforeInit</eventname>
                <listenerclassname>wcf\system\event\listener\SymfonyAuthListener</listenerclassname>
            </eventlistener>
        </import>
    </data>

    Wie im hardcoded-Teil bereits festgestellt, erhalte ich dabei folgende Meldung (wie im Post bereits beschrieben):

    Code
    Fatal error: Call to a member function setLanguageID() on null in /var/www/vhosts/x.com/forum.x.com/core/lib/system/WCF.class.php on line 696

    Einmal editiert, zuletzt von Stephan18 (12. September 2017 um 00:08)

    • Offizieller Beitrag

    Die Vorgehensweise zur Änderung des Benutzers über das genannte Event ist absolut korrekt, und wird von uns auch in diversen individuellen Erweiterungen so verwendet. Allerdings sollte es dabei zu keinem Fehler kommen, weshalb ich mir dies genauer ansehen muss und ggf. Änderungen teste, um das Problem zu umgehen.

  • Die Vorgehensweise zur Änderung des Benutzers über das genannte Event ist absikzt korrekt, und wird von uns auch in diversen individuellen Erweiterungen so verwendet. Allerdings sollte es dabei zu keinem Fehler kommen, weshalb ich mir dies genauer ansehen muss und ggf. Änderungen teste, um das Problem zu umgehen.

    Danke für das Feedback. Dann werde ich mal Abwarten.

    Bis dahin habe ich bei mir lokal folgendes gemacht:

    Code
    public function changeUser(User $user, $hideSession = false, $ignoreLanguage = false) {
    Code
    if (!$ignoreLanguage) WCF::setLanguage($this->languageID ?: 0);

    Somit kann ich dann in meinem event bei changeUser einfach den letzten Parameter auf true setzen. Somit wird die Fehlerquelle übersprungen. Läuft soweit ohne Probleme, da die Änderung explizit angegeben werden muss.

    norse

    Danke dir, auch wenn du nur das offensichtliche Ausgeschrieben hast. Es ging lediglich darum Alexander Ebert freundlich auf das Thema zu lenken und ein Feedback zu bekommen, ob und wann er es geplant hatte und was die Ziele sind. Das wir im Bereich Fehler sind ist ja leicht zu identifizieren ;)

    Gruß Stephan

    3 Mal editiert, zuletzt von Stephan18 (13. September 2017 um 13:58)

  • Es ging lediglich darum Alexander Ebert freundlich auf das Thema zu lenken und ein Feedback zu bekommen,

    Sorry, ich wusste nicht, dass Du mit derart subtilen Mitteln arbeitest....


    Gruß norse

    Zugang zu meinen Arbeiten und dem dazugehörigen Support bekommt Ihr bei Interesse hier und hier.

    • Offizieller Beitrag

    Es ging lediglich darum Alexander Ebert freundlich auf das Thema zu lenken […]

    Wenn wir mal davon absehen, dass ich das Thema eigenhändig hier hin verschoben habe:

    (Und Ja, das gesetzte Label ist nur intern sichtbar)


    Ansonsten gilt: Gras wächst auch nicht schneller, wenn man dran zieht.

Jetzt mitmachen!

Sie haben noch kein Benutzerkonto auf unserer Seite? Registrieren Sie sich kostenlos und nehmen Sie an unserer Community teil!