3 Stimmen

Mit Symfony2 geteilte Benutzer über mehrere Anwendungen hinweg

Ich habe mehrere symfony2-Anwendungen, die gemeinsame Entitäten teilen, aber unterschiedliche Datenbankeinstellungen verwenden. Jede dieser Datenbanken hat Tabellen user , user_role y role .

Hier ist der Haken: Ich möchte, dass sich dieser Benutzer bei folgenden Seiten anmelden kann app1 durch einen Besuch www.myproject.com/app1/login und nach Änderung der URL in /app2/ vorhandenes Token zu verwenden NUR wenn ein identischer Benutzer existiert in app2 Datenbank (gleicher Benutzername, Passwort und Salt). Derzeit wird nur nach demselben Benutzernamen gesucht, was, wie Sie sicher zugeben werden, ziemlich unbequem ist...

Ich kann nicht wirklich erkennen, wann refreshUser() aufgerufen wird... :-/

Alle Anwendungen verwenden dasselbe User y Role Einrichtungen und UserRepository .

Für jede Hilfe wären wir dankbar!

UserRepository:

class UserRepository extends EntityRepository implements \Symfony\Component\Security\Core\User\UserProviderInterface{
    /** @var User */
    private $user;

    public function loadUserByUsername($username) {
        /** @var $Q \Doctrine\ORM\Query */
        $Q = $this->getEntityManager()
        ->createQuery('SELECT u FROM CommonsBundle:User u WHERE u.username = :username')
        ->setParameters(array(
            'username' => $username
        ));
        $user = $Q->getOneOrNullResult();
        if ( $user == null ){
            throw new UsernameNotFoundException("");
        }
        return $this->user = $user;
    }

    public function refreshUser(UserInterface $user) {
        return $this->loadUserByUsername($user->getUsername());
    }

    public function supportsClass($class) {
        return $class === 'CommonsBundle\Entity\User';
    }

    public function findById($id){
        return $this->getEntityManager()
            ->createQuery('SELECT u FROM CommonsBundle:User u WHERE u.id = :id')
            ->setParameters(array(
            'id' => $id
            ))
            ->getOneOrNullResult();
    }
}

User#equals(UserInterface):

Ich weiß, es gibt einen schöneren Weg, um diese Methode zu schreiben, aber ich werde es neu schreiben, nachdem ich sehe, dass dies funktioniert :)

public function equals(UserInterface $user)
{
    if (!$user instanceof User) {
          return false;
    }
    if ($this->password !== $user->getPassword()) {
          return false;
    }

    if ($this->getSalt() !== $user->getSalt()) {
          return false;
    }

    if ($this->username !== $user->getUsername()) {
          return false;
    }

    return true;

}

5voto

Sgoettschkes Punkte 13051

Ihre Frage hat mich zum Nachdenken gebracht. Bei der Verwendung von symfony2-Sicherheit gibt es ein Problem: Entweder ist eine Session gültig, d.h. der Benutzer ist entweder als anonymer oder echter Benutzer authentifiziert, oder die Session ist ungültig.

Vor diesem Hintergrund sehe ich nicht, dass Ihr Ansatz so funktioniert, wie Sie es gerne hätten, denn nehmen wir an, Benutzer1 meldet sich an und verwendet app1. Jetzt wechselt er zu app2 und ist nicht in der Datenbank, was bedeutet, dass er keinen Zugriff haben sollte. Was ist nun zu tun? Die Sitzung für ungültig erklären? Das würde bedeuten, dass er sich erneut in app1 anmelden muss.

Wenn Sie Subdomains verwenden würden, könnten Sie Ihre Sitzung an diese Subdomain binden, aber das würde bedeuten, dass sich der Benutzer für jede Anwendung erneut anmelden muss.

Es gibt noch ein weiteres Problem: Es scheint, dass symfony2 die ID des Benutzers in der Session speichert, so dass Sie ohne Zugriff auf die app1-Datenbank nicht wissen können, wie das Passwort und die Rollen des Benutzers in der app1-Datenbank lauten, und diese nicht überprüfen können.

Ich vermute, dass die Sicherheit von symfony2 für ein solches Verhalten einfach nicht ausgelegt ist. Es erwartet, dass sich die Sitzung innerhalb der gesamten Anwendung auf denselben Benutzer bezieht.

Ich glaube nicht, dass symfony2 hier das große Problem ist sondern die allgemeine Handhabung mit php. Lassen Sie uns für einen Moment denken, was ich ohne symfony2 vorschlagen würde:

Wenn sich ein Benutzer anmeldet, speichern Sie Benutzer und Rollen in einem bestimmten Array in der Sitzung, wie:

user.app1 = array('username','password',array('role1','role2'))

Nun würde ich bei jeder Anfrage an app1 prüfen, ob user.app1 in der Sitzung ist und die Rollen von dort lesen. Wenn nicht, würde ich nach user.app2, user.app3 und so weiter suchen. Wenn ich keine finde, leite ich zum Login um. Wenn ich einen finde, würde ich die Datenbank abfragen, um den Benutzer mit demselben Benutzernamen zu finden, und die anderen Werte vergleichen. Wenn die Werte übereinstimmen, speichere ich alles in der Datenbank. Wenn nicht, den nächsten Benutzer aus der Sitzung prüfen.

Ich habe mir die Symfony Sicherheitsreferenz und Sie haben einige Erweiterungspunkte erhalten, so dass Sie vielleicht von dort aus weiterarbeiten können. Die form_login hat eine success_handler Das Hinzufügen des Arrays zur Sitzung, wie oben vorgeschlagen, sollte also dort erfolgen. Die Firewall selbst hat einige Parameter wie request_matcher y entry_point die verwendet werden könnten, um zusätzliche Prüfungen wie die oben genannten durchzuführen. Alle sind als Dienste definiert, so dass die Injektion des Entity Managers und des Sicherheitskontextes kein Problem sein sollte.

Ich persönlich denke, dass das Design an sich hier nicht optimal ist und Sie Ihren Code besser überarbeiten sollten, um entweder einen Benutzer für alle Anwendungen und verschiedene Rollen zu verwenden (denken Sie daran, dass Sie viele Entity Manager definieren und verschiedene Datenbanken verwenden können) oder sogar alle Datenbanken zu konsolidieren und alles in einer Datenbank zu speichern, wobei Sie acl verwenden, um zu verhindern, dass Benutzer die "falschen" Inhalte sehen.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X