Middleware doesn't work as expected - Laravel - php

I want to make a middleware to protect admin routes in laravel 5.2 app.
user_type isn't a field in users table in my db, but in a separate table :
Admin's user_type_id is 4
I made this middleware :
class AdminMiddleware
{
public function handle($request, Closure $next)
{
$authedUserID = Auth::id();
$user = User::query()
->leftjoin('users_user_types as uut', 'uut.user_id', '=', 'users.id')
->where('uut.user_id',"=","$authedUserID")
->get(['users.*',
'uut.user_type_id as userType'])->first();
if ($user['userType'] !=4)
{
return redirect('/home');
}
return $next($request);
}
}
and put this in $routeMiddleware array in kernel.php :
'admin' => \App\Http\Middleware\AdminMiddleware::class
and this is one of admin routes I want to apply my middleware on :
Route::get('ptyadmin', 'AdminController#show')->middleware('admin');
The Problem is that when I go to this route with admin user(user_type = 4) or normal user(user_type = 1) it redirects to /home in both cases !!
Why does this happen and how can I fix it ??

first method returns object
if ($user->userType !=4)
Also use selectinstead get
->select(['users.*','uut.user_type_id as userType'])->first();

It works when I put jwt.auth middleware in routes.php :
Route::get('ptyadmin', 'AdminController#show')
->middleware('jwt.auth')
->middleware('admin');
instead of putting it in AdminController :
public function __construct(User $user, JWTAuth $jwtauth)
{
$this->middleware('jwt.auth', ['except' => []]);
}

Related

Laravel 7.x Only the profile's Owner and some roles may enter or do action

I'm new at Laravel and I don't quite sure how to get User's session so he can see his own profile but can't be seen by other users except for the Admin role.
this is what I thought
profile/ProfileControllers.php
public function show(User $user)
{
if(Gate::allows('manageUsers')){
return view('Profile.Users.profile')->with([
'user' =>$user,
]);
}
if ($user->id === $user->id) {
return view('Profile.Users.profile')->with([
'user' =>$user,
]);
}
return redirect(route('home'));
}
I thought using $user->id == $user->id means the session user id = this id http://127.0.0.1:8000/profile/users/{id} but it is not and i can see the other user's profiles using a single user.
manageUsers inside the gate is the user admins like (cashier, sales, etc)
I reckon some other methods are using middleware in the web route. But I failed to understand what's to put on my middleware
routes/web.php
Route::namespace('Profile')->prefix('profile')->name('profile.')->middleware('?')->group(function(){
Route::resource('/users', 'ProfilesController', ['except' =>['store', 'create']]);
});
what I'm trying to approach is,
Only the owner of the profile and some roles can see the profile. and the guest will be redirected to home.
maybe you want something like this?
public function show(User $user)
{
if(Gate::allows('manageUsers')){
return view('Profile.Users.profile')->with([
'user' =>$user,
]);
}
if (auth()->user()->id === $user->id) {
return view('Profile.Users.profile')->with([
'user' =>$user,
]);
}
return redirect(route('home'));
}
Try $user->id == auth()->id()
You can create your own middleware and put your login theri.
php artisan make:middleware IsAdmin
Then register this to Kernel.php file
Inside middleware
If(auth()->user()->type == 'Admin'){
//Ruj your script inside if block , and instead of attribute TYPE
//you must put what you have used in databse to check if user
//is admin or not.
}

How to get computed variable from any model and controller in laravel?

I have 2 models: User and Account.
Account is an company account, it has a slug field. Slug is needed to determine which company the user is accessing. In example, route /account/*company_slug*/deals means that user trying to get an array of deals of company_slug company.
Each entity associated with a company has a field account_id. That's why I need to get an of the current account. Where should I do this and how?
In example, I get the middleware CheckIfAccountAcceptedForUser with the following code:
public function handle($request, Closure $next)
{
$account = Account::find($request->route()->parameter('account'));
abort_if(empty($account), 404) ;
abort_if(DB::table('account_user')
->where(function (Builder $query) use ($account) {
$query->where('account_slug', '=', $account->slug);
$query->where('user_id', '=', Auth::id());
})
->get()
->isEmpty(), 403);
return $next($request);
}
How to set the account_id globally for my application, if route is like /account/*account*/...?
Maybe this is not what you are looking for.
When you check account in middleware you make a query, after that you should make a new query in controller to take account data. In your situation you make 3 queries instead of 1.
You can check it in your account controller by one query.
Route:
Route::get('/account/{slug}/deals', 'AccountsController#deals');
Accounts controller:
public function deals($slug){
$account = Account::where('id', Auth::user()->account_id)
->where('slug', $slug)
->firstOrFail();
$deals = Deal::where('account_id', $account->id)->get();
return view('account.deals', compact('account', 'deals'));
}
It will always response 404 error if account with current slug doesn't exist or user can't access this account. Do you really need 403 response?
public function handle($request, Closure $next)
{
$account = Account::find($request->route()->parameter('account'));
abort_if(empty($account), 404) ;
abort_if(DB::table('account_user')
->where(function (Builder $query) use ($account) {
$query->where('account_slug', '=', $account->slug);
$query->where('user_id', '=', Auth::id());
})
->get()
->isEmpty(), 403);
//For global use in your all view file
View::share ( 'account_id', $account->id);
// to access account_id in controller
$request->request->add(['account_id' => $account->id]);
return $next($request);
}
In Controller
$account_id = request('account_id');

Laravel call route from controller

I am calling getting_started route after successfully login :
protected $redirectTo = '/getting_started';
Here is my getting_started route code :
Route::get('/getting_started','UserController#getting_started');
And controller code :
public function getting_started()
{
$id= Auth::id();
$user = DB::table('user_profiles')->where('user_id', '=', $id)->first();
if($user->dashboard_access == 0)
{
DB::table('user_profiles')
->where('user_id', $id)
->update(['dashboard_access' => 1]);
return view('user.getting_started');
}
return view('user.dashboard');
}
It works perfectly and show in url :
http://localhost:8080/getting_started
Now I actually want that if user.dashboard view is call it show in url like :
http://localhost:8080/dashboard`
And on getting_started view show :
http://localhost:8080/getting_started
It is possible to call dashboard route instead of :
return view('user.dashboard');
My dashobard route is :
Route::get('/dashboard',['middleware' => 'auth', function () {
return view('user.dashboard');
}]);
What I understand it is that you are looking for is this function
return redirect()->route('dashboard');
It's my understanding of your question which can be wrong. Maybe you are asking something else.
That called Redirection and especially you want to Returning A Redirect To A Named Route, you route called user.dashboard so you could redirect to it using redirect()->route(route_name) :
return redirect()->route('user.dashboard');
Hope this helps.

Laravel 5 Route binding and Hashid

I am using Hashid to hide the id of a resource in Laravel 5.
Here is the route bind in the routes file:
Route::bind('schedule', function($value, $route)
{
$hashids = new Hashids\Hashids(env('APP_KEY'),8);
if( isset($hashids->decode($value)[0]) )
{
$id = $hashids->decode($value)[0];
return App\Schedule::findOrFail($id);
}
App::abort(404);
});
And in the model:
public function getRouteKey()
{
$hashids = new \Hashids\Hashids(env('APP_KEY'),8);
return $hashids->encode($this->getKey());
}
Now this works fine the resource displays perfectly and the ID is hashed.
BUT when I go to my create route, it 404's - if I remove App::abort(404) the create route goes to the resource 'show' view without any data...
Here is the Create route:
Route::get('schedules/create', [
'uses' => 'SchedulesController#create',
'as' => 'schedules.create'
]);
The Show route:
Route::get('schedules/{schedule}', [
'uses' => 'Schedules Controller#show',
'as' => 'schedules.show'
]);
I am also binding the model to the route:
Route::model('schedule', 'App\Schedule');
Any ideas why my create view is not showing correctly? The index view displays fine.
Turns out to solve this, I had to rearrange my crud routes.
Create needed to come before the Show route...
There's a package that does exactly what you want to do: https://github.com/balping/laravel-hashslug
Also note, that it's not a good idea to use APP_KEY as salt because it can be exposed.
Using the above package all you need to do is add a trait and typehint in controller:
class Post extends Model {
use HasHashSlug;
}
// routes/web.php
Route::resource('/posts', 'PostController');
// app/Http/Controllers/PostController.php
public function show(Post $post){
return view('post.show', compact('post'));
}

how to pass variable to routes in laravel?

So i have a variable in my routes.php and i want to pass it to the route::get, this is my code for more details :
$user = User::find(Auth::user()->username);
Route::get('/services/here i want to put my variable', 'ServiceController#show');
so please if someone has any idea i will be very appreciative
The problem with variating your routes with something like:
$user = User::find(Auth::user()->username);
Route::get("/services/$user->username", 'ServiceController#show');
Is that you may enconter some problems in cases where the user does't exists. If you do that and go to your command line and execute:
php artisan routes
There will be no logged user so that route will be pointed to /services/. What you have to do to prevent those cases is to create a filter and process your route on it:
The route:
Route::get("/services/{username}", array('before' => 'user-must-be-logged-in', 'uses' => 'ServiceController#show'));
A filter to do some checks on it:
Route::filter('user-must-be-logged-in', function()
{
if ( ! Auth::check())
{
App::abort(404); /// user is not logged in, this route does not exist
}
if ( ! User::where('username', $username)->first() )
{
App::abort(404); /// user does not exists, this route does not exist
}
if (User::where('username', $username)->first()->id !== Auth::user()->id)
{
App::abort(404); /// selected is not the current logged user, this route does not exist
}
});
A controller doing whatever you need with it:
class ServiceController extends Controller {
public function show()
{
$user = User::where('username', $username)->first();
// now do whatever you need with your user;
}
}
assuming its $user you want to put in there
$user = User::find(Auth::user()->username);
Route::get("/services/$user", 'ServiceController#show');
swap single quotes for doubles and pass in your var (either that or drop out of your single quotes concat in with . your var

Categories