GeoLocation Restricted Routes For Laravel
- Laravel 5.5 or higher
- PHP 7.1 or higher
Navigate to your project's root folder via terminal or command prompt and execute the following command:
composer require laracrafts/laravel-geo-routes
Note: If you are using package discovery, you can skip the registration of the service provider and the alias as they do register themselves automatically, but don't forget to publish the configuration as described below.
- Register the service provider
Open your config/app.php
file and add this entry to the providers
array
LaraCrafts\GeoRoutes\GeoRoutesServiceProvider::class,
- Publish the configuration
While still in the same folder, execute this command in your terminal:
php artisan vendor:publish --provider="LaraCrafts\GeoRoutes\GeoRoutesServiceProvider"
To get started real quick, the allowFrom
and denyFrom
methods allow you to restrict access to routes depending on GeoLocations
- Allow access from specific regions
Route::get('/home', 'FooController@bar')->allowFrom('us', 'gb');
What the above example does, is allowing access to the /home
route only from the United States and the United Kingdom.
Alternatively we can do something like the following:
Route::get('/home', 'FooController@bar')->from('us', 'gb')->allow();
By default, all other countries will receive an HTTP 401 Unauthorized Error, to change this behavior you can use a callback as described in the callbacks section.
- Deny access from specific regions
So in the second example we are going to deny access only from specific locations, for instance: Canada, Germany and France
Route::get('/home', 'FooController@bar')->denyFrom('ca', 'de', 'fr');
Alternatively:
Route::get('/home', 'FooController@bar')->from('ca', 'de', 'fr')->deny();
Note: This package uses ISO Alpha-2 country codes.
Note: This package uses stevebauman's location package, please refer to it's official documentation for a detailed guide on how to configure it correctly.
Besides allowing you to control access to regular routes, the laravel-geo-routes
package also allows you to define route groups and do the same trick with them.
Please consider the following example:
Route::geo(['prefix' => '/en', function () {
Route::get('/', 'HomeController@index');
Route::get('/forums', 'ForumsController@index');
}])->allowFrom('dk', 'gb')->orRedirectTo('error');
Note: As you may have noticed, we are using the
geo
method instead of the defaultgroup
method which will behave the same way thegroup
method does, accepting an array of attributes for the first argument and a routes closure for the second one.
Note: Attributes methods can only be used after calling the
geo
method so instead ofRoute::name('english.')->geo(...);
you have to writeRoute::geo(...)->name('english.');
Note: Unless a rule is applied using the
from
,allow
,deny
,allowFrom
ordenyFrom
methods the route group will not be defined.
Under the hood, the allowFrom
and the denyFrom
methods set the geo
attribute on the routes which is an array containing the following parameters:
- [array]
countries
: The list of countries covered by the geo-constraint. - [string]
strategy
: Determines whether to allow or deny access, the value can only be allow or deny. - [array]
callback
(optional): The callback that will be invoked once the access is denied and its arguments.
Therefore, if you are more into verbosity, you can define your GeoRoutes
in the following way:
Route::get([ 'geo' => ['countries' => ['us', 'ca'], 'strategy' => 'allow', 'callback' => [$myCallback, $myArgs]] ], function() {
//
});
Your GeoGroups
may also be defined manually as in the following example:
Route::group([ 'geo' => ['countries' => ['us', 'ca'], 'strategy' => 'allow', 'callback' => [$myCallback, $myArgs]] ], function() {
//
});
As mentioned earlier, the default behavior for unauthorized users is an HTTP 401 Unauthorized Error
response, but you are still able to change this behavior by using callbacks.
To use a callback you have to simply add ->orCallback()
to the end of the GeoRoute constraint, like so:
Route::get('/forums', 'FooController@bar')
->allowFrom('de', 'ca')
->orCallback();
Note: You can also mixin with native router methods
Laravel-geo-routes has some useful built-in callbacks, we are going to list them below along with their use cases.
orNotFound
The orNotFound
callback will result in an HTTP 404 Not Found response for unauthorized visitors.
Route::get('/forums', 'FooController@bar')
->allowFrom('de', 'ca')
->orNotFound();
orRedirectTo
This callback accepts one required argument which has to be a valid route name. Thanks to this callback, you'll be able to redirect unauthorized visitors to a route of your choice.
Route::get('/forums', 'FooController@bar')
->allowFrom('de', 'ca')
->orRedirectTo('myRoute');
The callbacks above might not be enough for your own use case, so you might want to add custom callbacks, in this guide we will go through several methods to define custom callbacks.
- Create a new class, for instance
CustomCallbacks
- Add as many callbacks as you want to add, but be sure that all of your methods are
static
or you'll be facing problems - Open the
config/geo-routes.php
configuration file, and add your callbacks to the callbacks array, like so:
'callbacks' => [
'myCallback' => 'CustomCallbacks::myCallback',
'anotherCallback' => 'CustomCallbacks::anotherCallback'
]
Now your callbacks are ready, and you can start using them like so:
Route::get('/forums', 'FooController@bar')
->allowFrom('ca', 'us')
->orMyCallback();
Route::get('/blog', 'FooController@baz')
->denyFrom('fr', 'es', 'ar')
->orAnotherCallback();
Notice that we have added the
or
prefix and converted the callback name to studly case (e.g.myCallback
was converted toorMyCallback
), be sure not to forget this note as it is very important for your callback to work.
You may also load these callbacks using the parseCallbacks
method of the CallbackRegistrar
.
Example:
use LaraCrafts\GeoRoutes\Support\Facades\CallbackRegistrar;
public function boot()
{
CallbackRegistrar::parseCallbacks(MyCallbacksClass::class);
}
The loadCallbacks
method allows you to load an associative array of callbacks.
Example:
use LaraCrafts\GeoRoutes\Support\Facades\CallbackRegistrar;
public function boot()
{
$myCallbacksArray = [
'handyName' => 'myClass::myCallback'
//
]
CallbackRegistrar::loadCallbacks($myCallbacksArray);
}
The callback
method allows you to add a single custom callback, accepting a name and a callable.
Example:
use LaraCrafts\GeoRoutes\Support\Facades\CallbackRegistrar;
public function boot()
{
CallbackRegistrar::callback('foo', function () {
return 'Sorry, you are not authorized.';
});
}
We have tweaked the route:list
command and added new options in order to make retrieving the geo-constraint information easier. Below you will find the list of new options along with their usage examples.
Option | Value | Description | Usage |
---|---|---|---|
--geo |-g |
None | Show the routes geo specifications | php artisan route:list --geo |
--geo-only |
None | Display GeoRoutes only | php artisan route:list --geo-only |
--country |
String (ISO Alpha-2 Country Code) | Display only the routes that have a given country | php artisan route:list --country=[COUNTRY] |
--strategy |
String (allow|deny) | Display only the routes that have a given strategy | php artisan route:list --strategy=[STRATEGY] |
All contributions are welcomed for this project, please refer to the CONTRIBUTING.md file for more information about contribution guidelines.
Copyright (c) 2019 LaraCrafts.
This product is licensed under the MIT license, please refer to the License file for more information.