I want to prevent access to some of my app routes from other domain except listed. It success using below code:
$loginRoutes = function() {
Route::get('/', 'HomeController#index')->name('home');
};
Route::domain('domain1.com')->group($loginRoutes);
Route::domain('domain2.com')->group($loginRoutes);
Route::domain('localhost')->group($loginRoutes);
But the problem is when I call {{route('home')}}, the URL always becomes the domain at the last line of the routes.php(at above case is http://localhost ). How to make it to current domain?
My current solution:
if (isset($_SERVER["HTTP_HOST"]) && $_SERVER["HTTP_HOST"] == "domain1.com") {
Route::domain('domain1.com')->group($loginRoutes);
}elseif (isset($_SERVER["HTTP_HOST"]) && $_SERVER["HTTP_HOST"] == "domain2.com") {
Route::domain('domain2.com')->group($loginRoutes);
}
It's work but I think it's dirty. I have a lot of domains/subdomain and also the routes too.
I need solution on route directly, because I have a lot of routes, if I update each controller it's will take a long time. Maybe edit route provider or laravel vendor code is also no problem.
I am also using PHP 7.3 and Laravel 5.7
I actually use this routing for my domains.
Maybe this is not exactly what you asked, but you can try something like this
// To get the routes from other domains
// Always add the new domains here
$loginRoutes = function() {
Route::get('/', 'HomeController#index')->name('home');
};
Route::group(array('domain' => 'domain1.com'), $loginRoutes);
Route::group(array('domain' => 'domain2.com'), $loginRoutes);
Route::group(array('domain' => 'domain3.com'), $loginRoutes);
If you want to handle something at the domain level. In your controller (HomeController#index), you can get the current domain and do whatever you want. To get exact domain I have used like this:
class HomeController extends Controller
{
public function index()
{
$domain = parse_url(request()->root())['host'];
if ($domain == 'domain1.com'){
// do something
}
...
}
...
}
That way I can handle different things for each domain.
Just to make it more complete, we can take the domains from a table/query and dynamically create the routes.
$domains = Cache::get('partners')->where('status', '=', 'A')->where('domain', '<>', '')->all();
$loginRoutes = function() {
Route::get('/', 'HomeController# index')->name('home');
};
foreach ($domains as $domain) {
Route::group(array('domain' => $domain->dominio_externo), $loginRoutes);
}
It has been working for me. I hope to help you.
You can maybe try something like this :
Route::pattern('domainPattern', '(domain1.com|domain2.com|localhost)');
$loginRoutes = function() {
Route::get('/', 'HomeController#index')->name('home');
};
Route::group(['domain' => '{domainPattern}'], $loginRoutes);
If I understand your issue, you just want to filter domains. Using regex, you can do it. You could try the following code:
Route::domain('{domain}')->group($loginRoutes)->where('domain', '\b(domain1\.com|domain2\.com|localhost)\b');
Details:
\b: we get exactly the string.
\.: in regex, the character . means any character. So, we have to escape . using backslash.
Note:
You might get an error, because I can not check the results. Let me know any errors you encounter.
I want to prevent access to some of my app routes from other domain
except listed. It success using below code:
I think you are right with your thoughts about a better, more laravel-core based solution for this problem.
Every route handling method you define in a controller file recieves a request. In standard laravel this is an object of type Illuminate\Http\Request.
You can extend this class with a custom class - let's say "AdminRequest". This extended class than offers authorization methods which will check if the Auth:user has the correct role, session values or whatever you want in your app.
I guess this is more flexible and clean - in your controller you only have to change the definition of the request you recieve in that controller method. Validation messages and everything else can be wrapped in the custom request class.
See this also:
How to Use custom request (make:request)? (laravel) Method App\Http\Requests\Custom::doesExistI does not exist
Extend Request class in Laravel 5
for preventing access to a certain route, its a bad design to inject a Route into these structure:
Route::domain('domain1.com')->group($loginRoutes);
Route::domain('domain2.com')->group($loginRoutes);
Route::domain('localhost')->group($loginRoutes);
since it defines route multiple time, and only the last will be override the others.
you can check this by php artisan route:list .
the laravel way to handle this situation (access management ) is to use middleware
class DomainValid
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle($request, Closure $next)
{
$domain = $request->server->get('SERVER_NAME');
if (in_array($domain , ['domain1.com','domain2.com','localhost'] )) {
return $next($request);
}
abort(403);
}
}
and use it like this:
use App\Http\Middleware\DomainValid;
Route::get('/', 'HomeController#index')->name('home')->middleware(DomainValid::class);
so it will be only ONE home route.
Related
Hi
My application has to work with several domains. But I need certain routers to be ignored by ONE specific domain (base.domain).
As a result, the routers must work with different domains than the base.domain
Help please, spent a lot of time and could not do it.
// this code doesn't need to work with "base.domain"
Route::group(['domain' => '{domain}.{ltd}'], function() {
//some routes
});
if the domain will be "base.domain" - these are the routers you should ignore and use the other ones.
I tried using middleware instead of the Route::domain, but it's fail :(
You can do this via middleware, create a subdomain middleware for route group and check for base domain in middleware and restrict to proceed further, something like below:
In your routes/web.php
Route::middleware(['subdomain'])->group(function(){
//some routes for subdomains only..
});
Create a new middleware in your app and define in $routeMiddleware under app/Http/Kernel.php
In app/Http/Middleware/Subdomain.php
public function handle($request, Closure $next){
if($_SERVER['HTTP_HOST'] == config('app.base_domain')){
// redirect to base domain
return redirect(config('app.base_domain'));
//Or your can abort the request 404
abort(404,'Not Found');
}
return $next($request);
}
Define base_domain variable in your config/app.php
That's it!
I already have the answer, I would like to share the solution with those who need it.
How to use multiple domains with different pages and routes in Laravel?
I spent many hours looking for solutions, but nothing concrete, always with complex and messy codes, in the end I developed a practical solution with clean code.
1 - Firstly, it is necessary to centralize the laravel in a single domain, then you must point the other domains to the main domain, you can access your dns manager and use the CNAME record for this.
2 - In your Laravel you must create a Controller the home page with the following content, replacing what is necessary:
/**
* Display a listing of the resource.
*
* #return \Illuminate\Http\Response
*/
public function index(Request $request)
{
$origin = array("mydomain.com", "mydomain2.com");
$domain = parse_url(request()->root())['host'];
if (in_array($domain, $origin)) {
if ($domain === 'mydomain.com') {
return view('myview'));
}
if ($domain === 'mydomain2.com') {
return view('myview2'));
}
} else{
return view('unauthorized');
}
}
3 - Finally (optional), create a route with the urls that will be accessible only by that domain, do so:
Route::group(array('domain' => 'mydomain.com'), function () {
/* routes here */
Route::get('/', 'YouController#index');
});
Route::group(array('domain' => 'mydomain2.com'), function () {
/* routes here */
Route::get('/', 'YouController#index');
});
You must change mydomain.com and mydomain2.com to the domain you want, else{} you must replace unauthorized with a valid view, this is what will appear when the domain is not listed, if you want you can do the o server also shows nothing.
I have a middleware that detects if a user owns a tournament.
So, if user want to edit a tournament he doesn't own, he will get a 403.
Thing is I can't make difference between laravel.dev/tournament/1/edit, and laravel.devl/tournament/1
Off course, I could check the "edit" word in URL, but I would prefer other better param...
I tried method param in Request Object, but it is giving me GET for both, so I can't make difference...
Any Idea???
In your case, you can do like this:
$request->route()->getName();
Now you can do your logic based on this.
What about using a different HTTP method for edit, e.g PATCH or PUT and declaring two different routes, something like:
Route::get('laravel.devl/tournament/1', 'TournamentController#showTournament');
Route::put('laravel.dev/tournament/1/edit', 'TournamentController#editTournament');
Then in the TournamentController you can check if the user has rights to edit.
It sounds like you should just use route specific middleware instead of global middleware. See https://laravel.com/docs/master/middleware#assigning-middleware-to-routes. Then you can just do:
Route::get('/tournament/{id}/edit', ['middleware' => ['tournamentOwner'], function () {
//
}]);
Route::get('/tournament/{id}', ['middleware' => [], function () {
//
}]);
If it's a RESTful route, you can just do:
public function __construct()
{
$this->middleware('tournamentOwner', ['only' => ['edit']]);
}
So I've been using Laravel a lot lately, and it's great! But I've found myself banging my head against the keyboard on this issue I'm having.
I have this pattern:
Route::pattern('id', '(\d*|(me))');
And this route is required for a lot of my API calls. What it's supposed to do, is give consumers the option to simply append /me at the end of the call, to get info relating to them, so not having to use the userId. I can of course put this login in the controller, no problem, but I would love to be able to put some login in the "pattern", meaning that if this pattern is used, that I can check what userId "/me" correspons to and translate it. I want to do it this way to avoid having to write the same code translating "/me" in all controllers where this is used.
Hope someone has a clever solution out there! :-)
You can try using a Route filter. Something like this ought to work:
Route::filter('route_filter_name', 'F\Q\ClassName');
<?php namespace F\Q;
class ClassName
{
/**
* #param Illuminate\Routing\Route
*/
public function filter($route)
{
$userId = $route->getParameter('id');
if($userId == 'me' && ($user = Auth::user())) {
$route->setParameter('id', $user->id);
}
}
}
This is more specific to the route rather than your route pattern as it depends on what name you give the id parameter in each route that you want to use it in. An example route that uses it would look like this:
Route::get('/users/{id}', [
'before' => 'route_filter_name',
'uses' => 'UserController#showUserInfo'
]);
In a Laravel 4 app, i'm using subdomain routing around a bunch of Route::resource's like this:
Route::group(['domain' => '{account}.my.app'], function()
{
Route::group(['before' => 'auth'], function($account)
{
Route::resource('organisations', 'OrganisationsController');
Route::resource('clients', 'ClientsController');
Route::resource('domains', 'DomainsController');
});
});
In my auth filter i'm doing the following:
Route::filter('auth', function($route)
{
// you could now access $account in a controller if it was passed as an argument to the method
$account = $route->getParameter('account');
// share account variable with all views
View::share('account', $account);
// Auth::guest Returns true if the current user is not logged in (a guest).
if (Auth::guest()) return Redirect::guest('login');
});
Within my views I can now access $account, but if I want a call to URL::route() to be correct I have to manually pass the account variable, like URL::route('clients.show',['account' => $account]) otherwise it generates URLs like %7Baccount%7D.my.app.
This is a bit of a pain and doesn't seem that elegant, is there any other or better way to achieve this? I guess I could create my own route helper to use instead of the built-in one.
However, I also do redirects with Redirect::route() within controllers so I would also need to make updates here.
EDIT
As suggested in the comments it may be that extending the Route API is the best approach here. Does anyone have any suggestions how this should be done?
Thanks.