Symfony2 users have shared multiple applications

I have several symfony2 applications that have common entities but use different database settings. Each of these databases has tables user

, user_role

and role

.

Here's the catch: I would like this user to be able to log in app1

by visiting www.myproject.com/app1/login

and after changing the url to /app2/

to use the existing token ONLY if an identical user exists in the database app2

(same username, password, and salt). Currently, it only checks the same username, which you have to agree is rather inconvenient ...

I cannot see when refreshUser()

... is called : - /

All applications use the same user

, and role

the nature and UserRepository

.

Any help would be greatly appreciated!

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 () user interface:

I know there is a nicer way to write this method, but I rewrote it after seeing this work :)

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;

      

}

+3


source to share


1 answer


Your question made me think. When using symfony2 security, you have one problem: either the session is valid, that is, the user is authenticated as anonymous or real user, or the session is invalid.

So with that in mind, I don't see your approach working the way you would like, because let user1 log in and use app 1. Now it switches to app2 and is not in the database, meaning it is not must have access. What to do now? Invalid session? This means he must log in to app 1 again.

If you use subdomains, you can associate your session with that subdomain, but this will mean that the user must be logged in again for each application.

Another problem arises: it looks like symfony2 stores the user ID in the session, so without access to the app1 database, you cannot know what the password and user roles in the app1 database are and cannot check for it.

I suppose that symfony2 security was simply not built for this behavior. It expects the session to be associated with the same user throughout your application.

I don't think symfony2 is a big problem here , but general handling with php. Let's think for a moment what I propose without symfony2:



When the user logs in, store the user and roles in a specific array in the session, for example:

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

      

Now, on every request to app1, I would check if user.app1 is in the session and read roles from there. If not, I would check for user.app2, user.app3 and so on. If I don't find any, please forward the login. If I find it, I would query the database to find a user with the same username and compare other values. If there is a match, store everything in the database. If not, check the next user from the session.

I went through the symfony reference link and you got some extension points, so maybe you can work from there. form_login

got it success_handler

, so adding the array to the session as suggested above should be done there. The firewall itself has some parameters, such as request_matcher

and entry_point

, which can be used to add additional checks like the ones mentioned above. They are all defined as services, so implementing the object manager and security context shouldn't be a problem.

I personally think the design itself is not optimal here and you might be better off refactoring your code to use the same user for all applications and different roles (remember you can define many entity managers and use different databases) or even consolidate all databases and store everything in one database using acl to prevent users from viewing "wrong" content.

+5


source







All Articles