Multidomain Laravel App with partially same codebase - php

I am trying to implement a app, which provides two different login types based on the domain the user enters from. After successful login, the user gets a standard role and all users share the same codebase from here.
e.g.:
domain1.com leads to the standard auth scaffolding, regarding a login via email and pass
domain2.com leads to a controller which checks against an existing LDAP Login, gets additional info from the database at success and uses this info to log in the user via the standard auth api, additionally providing the role for the user.
So after the login is successful one way or the other, the user should share the same controllers, views, etc.
Is there any way to implement this? All answers I have found use some kinds of domaingroups to split the whole application.

You can accomplish this by using laravel's subdomain routing.
As an example, suppose you have two domains domain1.com and domain2.com. You have a login route login
Route::domain('domain1.com')->group(function () {
Route::get('login', function () {
// login
});
});
Route::domain('domain2.com')->group(function () {
Route::get('login', function () {
// login second method
});
});
// Common routes
You can then make your web server (Apache, Nginx, etc) have the same folder as the document root for both domains. So then, when a request comes to any of these domains, your web server will make your Laravel application handle the request, and Laravel will decide which page/auth method to use based on the domain.
So users from domain1 will use the first login route, and users of domain2 will use the second login route.
If you have static files (js,CSS, etc ) and you use the local filesystem driver, you may get cors errors, so it would be best to upload them to some CDN and cloud storages. If that's not possible, you would need to dynamically change the URL returned based on domain.

Related

How to keep/pass authenticated user session to other domain in Laravel

I have a multi tenancy build with Laravel. Now I have a system (main) website
main.com
where users can register.
After registration a tenant (subdomain) website is created and they are getting redirected to a new subdomain
tenantB.main.com.
Of course the Session is then deleted and they are not logged in anymore. I am trying to keep the session but the only solution I have found so far is to change the SESSION_DOMAIN in session.php config to
SESSION_DOMAIN=.main.com
The session will then remain on all subdomains but different tenants should not share their sessions. With that change if I login to tenantB.main.com I am also authenticated on tenantA.main.com which is not what I want.
Another approach I want to try is to send the session data when redirecting to the tenant subdomain (https://laravel.com/docs/7.x/redirects#redirecting-with-flashed-session-data):
redirect($this->redirectPath())->with('auth', 'abc')
But here I am stuck. How can I pass the current session? Or is that a totally wrong approach?
I would simply use a cookie. The information is best stored on the client side. That way the client is responsible for providing their own identification.
It is then the responsibility of your authentication middleware to check if the user has permission to access the current tenant subdomain.
Chances are laravel already is configured to use cookies for authentication. In that case, all you will have to do is to implement your own guard!
Auth::extend('tentantAuth', function ($app, $name, array $config) {
new TenantAuth(Auth::createUserProvider($config['provider']));
});
The TenantAuth class would then simply need to implement Illuminate\Contracts\Auth\Guard in order to be usable.
You can than use the extended authentication by updating your auth.php config file to use the driver 'tenantAuth'.
More information can be found under https://laravel.com/docs/7.x/authentication#adding-custom-guards

Proper way to route vue/ajax requests in laravel?

I'm new to laravel and making a web service that can function without javascript (if a user has it disabled or something.)
But it would be a better user experience to be able to perform certain actions without refreshing the whole page. I'd like to be able to say, send a form without reloading the page, or refresh notifications.
The options I can think of are:
1) Send the ajax to the same route as the pure html form, but with an extra variable and make my laravel respond with json when that variable is detected
2) Use the API route? Will this detect the currently logged in user?
3) Make new routes for everything ajax, even though they function the same as my current routes (aside from returning a view)
Also, does the CSRF token work multiple times in a row, or do I need to disable that to handle multiple ajax form posts in a row without page refreshes?
I recommend keeping the routes separate, both to prevent weird caching bugs and for your own sanity as the code changes over time.
Laravel is set up out of the box to let you define web routes in routes/web.php and api routes in routes/api.php. Routes defined in your api.php file will be available at /api/* by default. It's much easier to manage changing the application this way, rather than trying to make your controllers do both views and api responses.
With Laravel Passport, your API routes can detect the currently logged in user via the auth:api middleware when combined with adding the Laravel\Passport\Http\Middleware\CreateFreshApiToken to your web middleware group.
https://laravel.com/docs/5.7/passport#consuming-your-api-with-javascript
An easy way to manage the duplicated controllers (one for web and one for api) is to put Api controllers in their own namespace, with php artisan make:controller Api/FooController. You can even set up your Api routes to look for controllers in this namespace by default by editing RouteServiceProvider.php.

AUTH, logging in and out of fat free framework and handling sessions and securing pages

The documentation doesn't talk much about logging in and out and handling security in general.In Symfony, you can secure pages of your site via a YML file. Does F3 have anything like that?
What is the recommended way to secure pages and handle a logged in user? I liked basic Auth, but it isn't very flexible, and it seems logging out is trickier. So I decided to set up a form for login/logout.
I would have assumed that Auth automatically creates a session, but from what I can tell it doesn't. So does that mean I need to manually do it?
Also, how do I block non authenticated visitors from the site? Do I need to add a SESSION check in each route?
The freedom when using F3 is that you can/must implement this on your own.
You got multiple options here or can create some other creative solutions too, if your project requires it. The included Auth plugin doesn't create a SESSION of course, because it cannot know if you want to use a SESSION to track your users or maybe use other solutions (cookie, JWT, etc).
So in most cases you need to create an Auth controller where you check if a user is logged in or not - here you would probably use the Auth plugin and create the SESSION if you want that. From there on you got serveral other options.. just to name a few:
use a base controller, that your other controllers will extend (or a Trait) and add a beforeroute there, where you'll check if the user is logged in and allowed to access that ressource.
check the user rights in the front controller (index.php) and don't even register the routes that the user has no access to.
use a 3rd party plugin to add access checks to routes, i.e. f3-access
use another middleware router to pre-flight the current request and add auth checks to multiple routes at once

Laravel - Authentication via external API

Firstly I'm a real beginner with Laravel so I will try to describe my problem as best as I can.
I am building a website using Laravel however the information on users will not be stored on my server but rather externally on another server.
The only way to access the user's data is through an external API; I am not allowed access to their database. The API request returns a token and I use this token to check with their server to see if the user is logged in.
My question is: how do I authenticate the user so that I can still use Laravel's out of the box guards.
It's really handy to use methods like Auth::check() to determine if the user is still logged in.
You'll either need to modify Laravel's default authentication middleware in app/Http/middleware/Authenticate.php or you'll need to create your own middleware class that runs the authentication that you need. Create a class in the app/Http/middleware folder and register that middleware. https://laravel.com/docs/master/middleware

Multiple sessions on the same browser for one single webapp

Can the same user have multiple sessions to the same app in the same browser as long as another field is added to the authentication process (email, password and website_id)?
I'm building a PHP app that allows the creation of multiple onepage websites. Each website should serve as standalone sites, with different content but they all have the same backend. Each website has a separate set of users/customers. A user can signup on any website but the websites don't necessarily share a user base. This means that a user can go to site1.domain.com and register, and then would have to register again if they wish to visit site2.domain.com.
They will probably register using the same email address, so my user table allows for duplicate email addresses as long as they're not in the same website.
This is sort of a very simple CMS. Kinda like what magento does with multiple websites running under the same instance. They also allow each separate site to have they're own customer base.
I plan to use Laravel for this project. My current approach is this:
Modify the provided user authentication functionality to add the site_id field. This means the user can register with the same email address in multiple sites, and can also log in to all those sites separetly. If they're logged in to site1 and visit site2, they have to log in again and have two separate sessions for what would appear to them as two different apps, but is just the one.
In theory this seems possible to me. A cookie is created for each separate subdomain once they login, which wouldn't work on a different subdomain. I feel like I'm missing something big though, I've never done something similar to this and always relied on Laravel to handle all the session stuff for me. Is this possible without some heavy hacking to the Laravel codebase?
UPDATE
These are my constraints:
The desired affect is that each website appears to be a separate application alltogether and not related at all to the others but all tied to the same backend and with the same routing/views.
userbase and user session cannot be shared between sites. I can make it so a user registers once and can login to every site, but I don't want that. A user should be able to visit every website separately.
every website will have a different subdomain, or in same cases, a different domain alltogether.
PHP sessions are tied to the domain name, so they will automatically have different sessions for each of your apps. You can use route-model binding with a custom resolution to determine the app based on the domain.
routes.php
Route::group(array('domain' => '{site}.com'), function() {
//routes go here
});
RouteServiceProvider (in boot method)
$router->bind('site', function ($value) {
return App\Site::where('custom_domain', $value)->first();
});
This is based on the assumption that you have a Site model with a field in the database called custom_domain. All of the routes available inside the group will have access to the Site using dependency injection. You can adjust the model and field based on your app needs.
You can use the model to customize the login-page for each app, and the apps will have independent sessions for each one.
I've also heard great things about the Landlord package. You use a middleware to define which Site the user is, based on the url. Once that is set, all eloquent queries will be automatically scoped based on the site_id in the database. So User::all() would only return users for the current site.

Categories