hipsterjazzbo / Landlord

A simple, single database multi-tenancy solution for Laravel 5.2+
MIT License
615 stars 138 forks source link

Same email registration over different tenants #74

Closed themanish closed 6 years ago

themanish commented 6 years ago

I have a situation where I need an user to be able to register separately with two different tenants. I'm being able to restrict login one user of a tenant to other, but not to register same user to two different tenants.

Thanks!

HelgeSverre commented 6 years ago

You could allow for duplicate users in the database linked to different tenant_ids.

When you recognize a user that is linked to multiple tenants has entered their email/username into the login form via an AJAX check to an endpoint that tells you "is this username/email linked to multiple tenants, if so, give me a list of them) then present the tenants in a dropdown, which you use on the login action in your LoginController to decide which user you are logging into.

Makes sense?

themanish commented 6 years ago

How do I allow duplicate users linked to different tenant_ids? Do I need to customize laravel auth for that? Or, is there anything useful in Landlord?

HelgeSverre commented 6 years ago

You need to customize the default laravel auth.

themanish commented 6 years ago

Any reference for that? Or, a brief idea?

HelgeSverre commented 6 years ago

Add a route that does this exact thing:

  1. Fetch username from request
  2. Search user table for that username
  3. If returns more than 1 entry return the tenants that match.

In the logincontroller do this:

Override the login method:


    protected function getMatchingUser($tenantId, $username, $password)
    {
        // Either username or email, whatever you're using
        return User::where("username", $username)
            ->where("tenant_id", $tenantId)
            ->where("password", bcrypt($password))
            ->first();
    }

    public function login(Request $request)
    {
        // Get the user that matches the tenant, the tenant_id
        // should be passed in your login form when you detect that
        // the user trying to login has multiple accounts,
        // i suggest performing an ajax check before submitting the
        // login form that checks this and returns a list of tenants
        // and show these in a dropdown (<select name="tenant_id">),
        // the user then has to which tenant to login to.
        $user = $this->getMatchingUser(
            $request->get("tenant_id"),
            $request->get("username"),
            $request->get("password")
        );

        if ($user) {

            // We simply login the user with the login method, so we can specify
            // the user model to login, we've already "authenticated" the user in the previous call
            $this->guard()->login($user);
            return $this->sendLoginResponse($request);
        }

        // If the login attempt was unsuccessful we will increment the number of attempts
        // to login and redirect the user back to the login form. Of course, when this
        // user surpasses their maximum number of attempts they will get locked out.
        $this->incrementLoginAttempts($request);

        return $this->sendFailedLoginResponse($request);
    }

In the registerController, simply remove the validation that forces the email to be unique.

If you've got any question feel free to ask.

HelgeSverre commented 6 years ago

The idea is that when a user that has multiple accounts linked to different tenants with the same username/email, he will be notified on login (ajax call to the endpoint i mentioned that returns matching tenants), it populates a dropdown which the tenants he can login to, and the user is then logged into that tenant in the LoginController.

themanish commented 6 years ago

Hey thanks so much for helping! :) Though, I want to point out one thing that, Landlord pretty much helps in logging in tenant specific users. Only problem is with registering duplicate ones. And I think I got a solution, and am trying to implement it. As you said to remove unique validation, I would rather prefer to use custom validation rule which laravel provides as below (yet not implemented, ongoing):

'email' => Rule::unique('users')->where(function ($query) {
    $query->where('account_id', 1);
})