Laravel preventing user from accessing other users resource **url - laravel

I am passing a specific resource in the url, for ex.
https://www.example.com/{companyID}
And in the controller I can access the resource by
public function index($companyID)
{
// Code Here
}
I need to block users from changing the url and accessing other companyIDs from the system. Currently its open and is a security risk. I checked out Laravel Gate and Policy's but fail to see how this could be implemented for my case.
What I am really looking for is something in the AuthServiceProvider boot method that can check if the user really is the owner of the resource before continuing with the code.
Any help?

As mentioned before, you can do that by creating a Middleware that checks if your resource should be available to the logged in user.
See some details about middleware here
First, create a Middleware via php artisan, like this
php artisan make:middleware AuthResource
Next, add it to your App\Http\Kernel.php
protected $routeMiddleware = [
...
'AuthResource' => \App\Http\Middleware\AuthResource::class,
];
In your routes, you can now do the following:
Route::get('{companyID}', ['uses' => CompanyController#index, 'middleware' => 'AuthResource']);
That way, your AuthResource middleware is used whenenver the route is called.
In your App\Http\Middleware\AuthResource.php you have to change the code from
public function handle($request, Closure $next)
{
return $next($request);
}
to something that checks if the resource is available to the currently logged in user.
I assume that your companies table has a field user_id, which links the Company to a User. If your data structure is different, you need to change the code accordingly.
public function handle($request, Closure $next)
{
if ($request->route('companyID')) {
$company = Company::find($request->route('companyID'));
if ($company && $company->user_id != auth()->user()->id) {
return redirect('/');
}
}
return $next($request);
}
That way we check if the a route parameter with the name companyID exists, and if it does we check if it is available to the currently logged in user. If no companyID parameter is available, the page can be loaded without any restrictions.
That way you can copy/paste the code within the middleware for any parameters so that the middleware does work for multiple resources (not only companies).

This is can be done easily by middleware. But I’ll do this in more understandable way.
I assume that your user has one to one relationship with company.
So first create the relationship,
In your User model,
Public function company() {
return $this->hasOne(‘App\Company’);
}
Company model
Public function user(){
return $this->belongsTo(‘App\User’);
}
So, now make Authenticate by running php artisan make:auth . more details on Authenticate
And now in your controller,
public function index($companyID)
{
$current_user = Auth::user();
$user_company = $current_user->company; // get the current user's company details
If($companyID == $user_company->id){
// do something
}
}

Related

how to get auth information in AppService provider?

I'm trying to give a condition is user suspend, user should redirect to login page if user in login state.
I have tried to give a check in AppServiceProvider like below
public function boot()
{
if(auth()->user()->is_deleted === true) return redirect('/logout');
}
Problem is in AppServiceProvider I'm not getting any auth information. How I can solve this problem ?
You can do this better with Middlewares,
Create a middleware CheckIfDeleted
php artisan make:middleware CheckDeleted
Open the CheckIfDeleted and update the handle method:
public function handle(Request $request, Closure $next)
{
if(auth()->check() && auth()->user()->is_deleted === true){
Auth::logout();
$request->session()->invalidate();
$request->session()->regenerateToken();
return redirect('some error page?');
}
return $next($request);
}
Open the Kernel.php (app/http folder), then add the new middleware in the web section (protected $middlewareGroups):
\App\Http\Middleware\CheckIfDeleted::class,
I also recommend you implement the softDelete of laravel, you can use this guide from stack: Laravel Soft Delete posts
In this case if the user is deleted, they will get an error message, and you will still keep the record of the user :)

Can't access user model in middleware

I created a custom middleware for checking if request is submitted by user who owns the resource or owned by admin.
Route::middleware(['web', 'selforadmin'])->group(function () {
Route::post('users/update-account/{id}', 'UsersController#UpdateAccount');
Route::post('users/update-email/{id}', 'UsersController#UpdateEmail');
Route::post('users/update-password/{id}', 'UsersController#UpdatePassword');
});
and then the middleware handler:
public function handle($request, Closure $next)
{
print_r($request->all());
print_r($request->user());
dd();
return $next($request);
}
But I don't know why user model is not accessible here. I read that request needs to pass from web middleware first so I did but still can't access this middleware.
It gives null on $request->user() or Auth::user()
I am using Laravel 5.4
EDIT:
Middleware is being called as I see other inputs. Only Auth is empty. And User is logged.
You can't access using models directly in middleware. You need to define a terminate method in your middleware to perform some processing after response has been sent to browser.
public function terminate($request, $response)
{
// Your code ...
}
If user is not logged in it will always return null.
There are two solution for this.
First is, check if $request->user() is not null.
public function handle($request, Closure $next)
{
if($request->user())
{
// do your stuff
}
else
{
// do otherwise
}
return $next($request);
}
Second is, add auth middleware before your middleware to assure that only logged in users are allowed.
Route::middleware(['web', 'auth', 'selforadmin'])->group(function () {
// .....
}

Laravel 5.4 Sessions and Auth::user() not available in controller's constructor

I would like to use a User class throught the application. So, I would like to create CustomUser and then inject it into controllers that need it (it would be most of them).
Now, I create an empty instance in serviceprovider. Next, I want to fill it with data that are already saved in Auth::user(). After long time I have not found where to do it.
Auth::user() is empty in middlewares, but is filled with the user data in controllers. I am missing the step where Laravel queries the database and fills Auth:user() with data. I want to avoid making the same query again.
Thanks for any help!
You can use base controller with __get() method. For example:
class Controller
{
public function __get(string $name)
{
if($name === 'user'){
return Auth::user();
}
return null;
}
}
And in the child controllers can call $this->user
Since Laravel 5.3, you do not have access to sessions in controller constructors. This is because the middleware has not been run yet. I know it's difficult to locate, but in the migration documentation from 5.2 > 5.3 (you're probably on 5.4), it shows that the proper way to resolve data from sessions (which auth() is just a wrapper around a session() call to get the user), is to use the following method:
class MyController extends Controller {
protected $user;
public function __construct() {
$this->middleware(function ($request, $next) {
$this->user= auth()->user();
return $next($request);
});
}
}
Then $this->user will reference the auth user to any methods inside of this controller.
Hopefully his helps.
In Laravel 5.6 i used this
$this->middleware(function ($request, $next) {
$id = Auth::user()->id;
$res = $this->validateAnyFunction($id);
if(!$res){
//to redirect to any other route
return $next(redirect()->route("any")->with("failed","Invalid")->send());
}
//this is used to proccess futher funcitons of controller
return $next($request);
});

Laravel how to execute specific function every time a specific controller's functions are used

I am running laravel and i just implemented PHP Excel in order to export excels with data. For security reasons i want to redirect the user if his facebook id is no match with "my administrator facebook id".
My controller is named ExcelController and it has different functions inside it.
I do not want to use the below code inside every function so i am trying to find something to execute like __construct() - everytime this controller is accessed :
if(Auth::user()->facebook_id != env('facebook_id_admin_access')) {
return redirect()->route('home');
}
env('facebook_id_admin_access') is an .env variable(like a constant) with the facebook id i want to give access so it can use the specific controller.
I tried creating a public function __construct(){} in the controller and put the above code block but it doesn't get called.
Is this possible and how? Should i use middleware for that?
EDITED QUESTION
1) Created a middleware CheckAdminAccess
*/
public function handle($request, Closure $next)
{
if(Auth::user()->facebook_id != env('FACEBOOK_ID_ADMIN_ACCESS') || !Auth::check()) {
return redirect()->route('/');
}
return $next($request);
}
2) Updated in app\http\kernel.php to
protected $routeMiddleware = [
'admin_access' => 'App\Http\Middleware\CheckAdminAccess',
];
3) Updated in routes.php :
Route::get('/output/completed', 'ExcelController#completed')->middleware('admin_access');
But it doesn't seem to work, did i forgot anything?
After creating a middleware,
To make it work i changed in my routes.php from :
Route::get('/output/completed', 'ExcelController#completed')->middleware('admin_access');
To :
Route::group(['middleware' => ['auth','admin_access']], function() {
Route::get('/output/completed', 'ExcelController#completed');
});

Laravel 5 restrict access to pages using middleware

I am working on a laravel project and i need to restrict access to some pages such that only authenticated users can view that page.
To do this, created a middleware: php artisan make:middleware OnlyRegisteredUser
and registered it in the $routemiddleware inside App\Http\kernel.php as
'onlyregistereduser' => \App\Http\Middleware\OnlyRegisteredUser::class,
and this is the class. it redirects user to auth/login if not logged in
public function handle($request, Closure $next, $right=null)
{
$user = $request->user();
if ($user && $user->onlyregistereduser()) {
return $next($request);
}
return redirect('auth/login');
}
Here is my route:
Route::get('admin/poem', ['middleware' => 'onlyregistereduser:admin', 'uses'=>'PoemsController#poem']);
admin is a parameter passed to my middleware. It is taken from my user model which has an `enum' column as follows:
public function up()
{
Schema::create('users', function (Blueprint $table) {
//...
$table->enum('rights', ['admin', 'guest'])->nullable();
// ...
});
}
Now to restrict access to some of my controller methods, e.g create, i added a constructor to my PoemsController as shown:
public function __construct()
{
$this->middleware('onlyregistereduser');
}
My problem now is that this caused every single route to the PoemsController to redirect me to the login page. And again after login in, it doesn't take me to the page i intended to visit. it takes me instead to the home page. What i want is to restrict access to only some of the controller methods and not all of them and to be able to redirect to the intended page after user login.
I hope you understand my problem.
Any help will be greatly appreciated.
Remove the middleware from constructor, you don't have to add middleware to both route and costructor. That should solve your ". What i want is to restrict access to only some of the controller methods and not all of them" issue.
For othe issue modify your middleware like this
public function handle($request, Closure $next, $right=null)
{
$user = $request->user();
if ($user && $user->onlyregistereduser()) {
return $next($request);
}
$request_url = $request->path();
session()->put('login_refferrer', $request_url);
return redirect('auth/login');
}
and before redirect user after login
if(session()->has('login_refferrer')){
$url = session()->pull('login_refferrer');
return redirect($url);
}

Resources