Middleware for user roles in Laravel - laravel

I am creating an Admin Panel and I have problem with the access , I am using One-to-Many relation and I have the table user with role_id=3.
This middleware works correctly but I need to protect the routes correctly.
class Administrador
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #param string|null $guard
* #return mixed
*/
public function handle($request, Closure $next, $guard = null)
{
if (Auth::guard($guard)->guest()) {
if ($request->ajax()) {
return response('Unauthorized.', 401);
} else {
return redirect()->guest('/administrador');
}
}
return $next($request);
}
}
The routes are correctly set, but I don't know how to send the user's role in this Middleware.

...
EDIT
If you want to combine in one middleware Administrador it would be:
class Administrador
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #param string|null $guard
* #return mixed
*/
public function handle($request, Closure $next, $roles = null, $guard = null)
{
if (Auth::guard($guard)->guest()) {
if ($request->ajax()) {
return response('Unauthorized.', 401);
} else {
return redirect()->guest('/administrador');
}
}
$roles = explode('|', $roles);
if (! in_array(Auth::guard($guard)->user()->role_id, $roles) {
return response('Unauthorized.', 401);
}
return $next($request);
}
}
Example usage on route:
Route::group(['middleware' => 'administrador:1|2'], function () {});
administrador:1|2 replace the value with your role ids separated by |, if you want to use another guard then you can pass it as second parameter, example: administrador:1|2,custom_guard. This way you can define multiple roles that able to access your admin screen.
If you would rather want to use one fixed role:
class Administrador
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #param string|null $guard
* #return mixed
*/
public function handle($request, Closure $next, $guard = null)
{
if (Auth::guard($guard)->guest()) {
if ($request->ajax()) {
return response('Unauthorized.', 401);
} else {
return redirect()->guest('/administrador');
}
}
if (Auth::guard($guard)->user()->role_id !== 3) {
return response('Unauthorized.', 401);
}
return $next($request);
}
}

Related

Authenticate extends Middleware redirect me if i have permission

Hello please can explain me why it happedned . i hve make middleware and was work ok but suddenly stop and redirect me any way problem in method where Authenticate .php
class Authenticate extends Middleware
{
/**
* Get the path the user should be redirected to when they are not authenticated.
*
* #param \Illuminate\Http\Request $request
* #return string|null
*/
protected function redirectTo($request)
{
if (! $request->expectsJson()) {
return route('login');
}
}
}
this return me to login if i logged not allow for user he have permisson to go this
middleware
class AdminMiddleware
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure(\Illuminate\Http\Request): (\Illuminate\Http\Response|\Illuminate\Http\RedirectResponse) $next
* #return \Illuminate\Http\Response|\Illuminate\Http\RedirectResponse
*/
public function handle(Request $request, Closure $next)
{
if (Auth::check()){
if (Auth::user()->user_type == 1){ //Any Manger Can Access only Not Users
return $next($request);
}else{
return redirect()->back();
// abort(403);
}
}else{
return redirect()->back();
}
}
}
and user_type == 1 was try in middle ware dd(Auth::user()); but if put it in side method redirectTo
dd(Auth::user());
return info bout user but not return nothing direct go to login in Authenticate ,
Route::group(['middleware' => 'auth:admin'], function () {
Route::get('admin/dashboard', function () {
return view('admin.index');
})->name('admin.dashboard');
and befor it was work ok . what problem !

Can I use dynamic model on middleware?

I have 2 routes that requires a person to be tagged to access the discussions.
http://localhost:8000/api/fieldReports/{fieldReport}/discussions
http://localhost:8000/api/agendas/{agenda}/discussions
Currently, I have created this middleware, but instead of pointing right to a specific model, and duplicate it for each model with the exact same functionality, I want it to be more reusable.
Middleware\ForbidUntaggedUser.php
class ForbidUntaggedUser
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle(Request $request, Closure $next)
{
$user = $request->user();
$report = $request->report; // <-- I hardcoded the model, I want this to be dynamic
// The `taggedUsers` remains the same (identical) for each model that has tagging system on it.
if (!$report || !$report->taggedUsers->contains($user->id)) {
return response()->json('Your action is unauthorized.', 403);
}
return $next($request);
}
}
I've tried to use Policy but it doesn't work, so I think I need a middleware for this.
Policies\FieldReportDiscussionPolicy.php
class FieldReportDiscussionPolicy
{
use HandlesAuthorization;
/**
* Determine whether the user can view any models.
*
* #param \App\Models\User $user
* #return mixed
*/
public function viewAny(User $user, FieldReport $fieldReport)
{
return $user->can('view any fieldReportDiscussion')
&& $fieldReport->taggedUsers->contains($user->id);
}
... // and so on..
}
Controllers\FieldReportDiscussionController.php
class FieldReportDiscussionController extends Controller
{
protected $model;
/**
* Create new instance.
*
* #return void
*/
public function __construct()
{
$this->authorizeResource(
FieldReportDiscussion::class,
['fieldReportDiscussion', 'fieldReport'] // This gave me error "Array to string conversion"
);
$this->model = new FieldReportDiscussion;
}
/**
* Display a listing of the resource.
*
* #return \Illuminate\Http\Response
*/
public function index(FieldReport $fieldReport)
{
$discussions = $this->model->registries($fieldReport)->paginate(100);
return response()->json($discussions);
}
}
I need the dependency injection on the controller because the route is nested with each model as the parent, like this one..
routes\api.php
Route::apiResource('fieldReports', FieldReportController::class);
Route::apiResource('fieldReports.discussions', FieldReportDiscussionController::class)->except(['update'])->parameter('discussions', 'fieldReportDiscussion');
So, what's the solution for this? Can I make it dynamic (the first request object)?
I think you're on the right track with using middleware, although you'll need some conditional checks, something along the lines like:
class ForbidUntaggedUser
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle(Request $request, Closure $next)
{
$instance = null;
if ($request->report !== null) {
$instance = $request->report;
} else if ($request->agenda !== null) {
$instance = $request->agenda;
}
if (!$instance || !$instance->taggedUsers->contains(auth()->id())) {
return response()->json('Your action is unauthorized.', 403);
}
return $next($request);
}
}
If you have named correctly your params in your controller i.e. in a resoruce controller
<?php
namespace App\Http\Controllers;
use App\Models\Agenda;
class AgendaController extends Controller
{
public function show(Agenda $agenda)
{
....
}
}
The first parameter of your request will be the named model, so you can get the model with the getModel() function, if you are not sure, you can search it with findModel() function.
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Http\Request;
class MyMiddleware
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure(\Illuminate\Http\Request): (\Illuminate\Http\Response|\Illuminate\Http\RedirectResponse) $next
* #return \Illuminate\Http\Response|\Illuminate\Http\RedirectResponse
*/
public function handle(Request $request, Closure $next)
{
$model = $this->getModel($request);
$tryGetModel = $this->findModel($request);
}
private function getModel(Request $request) : Model|null
{
$modelParameterName = $request->route()->parameterNames()[0];
return $request->$modelParameterName ?? null;
}
private function findModel(Request $request) : Model|null
{
foreach($request->route()->parameters() as $param)
{
if($param instanceof Model)
return $param;
}
return null;
}
}

My Middleware redirects to home page everytime

I have made a quiz when the user unlocks the quiz then only the user can access the quiz page suppose 127.0.0.1:8000/quiz1. But I have unlocked the quiz, then too my middleware takes me to /home page.
I have tried this logic but it didn't worked.
<?php
namespace App\Http\Middleware;
use Closure;
use App\Theme_User;
use App\User;
use Auth;
class UnlockMiddleware
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle($request, Closure $next)
{
$user = auth()->user()->id;
$theme_user = Theme_User::find($user);
if($theme_user->unlocked == 1){
return $next($request);
}
else {
return redirect('/login');
}
}
}
In my Theme_User there is user_id and unlocked stored but that is not working for me.
You need to check if they are logged in first, like so with \Auth::check()...
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle($request, Closure $next)
{
if(\Auth::check()) {
$user = \Auth::user()->id;
$theme_user = Theme_User::find($user);
if($theme_user->unlocked == 1){
return $next($request);
}
// Logged in but not unlocked
}
else {
return redirect('/login');
}
}
I have no idea what the logic is meant to be behind logged in but not unlocked, you'll need to fill that gap
It might be worth checking if user is logged in before trying to get user id from auth.
public function handle($request, Closure $next)
{
if(auth()->check()) {
$user = auth()->user()->id;
$theme_user = Theme_User::find($user);
if($theme_user->unlocked == 1){
return $next($request);
}else{
return redirect('whatever_page_if_user_is_logged_in_but_not_unlocked');
}
}else {
//this only happens if user is not logged in
return redirect('/login');
}
}

Object of class Illuminate\Routing\Redirector could not be converted to string

On my laravel project when, I'm trying to authorize, shows me error exception
"Object of class Illuminate\Routing\Redirector could not be converted to string"
It indicates me to my Middleware Class
use Closure;
use Illuminate\Support\Facades\Auth;
class RedirectIfAuthenticated
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #param string|null $guard
* #return mixed
*/
public function handle($request, Closure $next, $guard = null)
{
if (Auth::guard($guard)->check()) {
return redirect('/dashboard');
}
return $next($request); //This row could not be converted to string
}
}
and to this file
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Support\Facades\Storage;
class VerifyAppInstalled
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle($request, Closure $next)
{
if (config('database.transfer_mode') == "1") {
if (password_verify($request->server('SERVER_NAME'), getOption('app_key', true))
&& password_verify(strrev($request->server('SERVER_NAME')), getOption('app_code', true))) {
return redirect('/transfer/restore');
}
return redirect('/transfer/ready');
}
if (config('database.installed') == '%installed%') {
return redirect('/install');
}
if (Storage::exists('images/update')) {
return redirect('/update-progress');
}
\App::setLocale(request()->session()->get('locale', getOption('language')));
return $next($request);
}
}
Please help me what is wrong here?
enter image description here

Webpage routing according to user type in laravel

I have used make:auth command to create basic register and login. I have created an extra field in register page which gets user type*(admin,employee or visitor)*.
Now my problem is I need to navigate to three different page for each of them by accessing that user type from the users table in database. Any help any suggestion are most welcome.
As far as I know, Laravel 5 comes with \App\Http\Middleware\RedirectIfAuthenticated middleware class which intended to do redirection once user logged in.
So in this case, the handle function of the middleware would be
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #param string|null $guard
* #return mixed
*/
public function handle($request, Closure $next, $guard = null)
{
if (Auth::guard($guard)->check()) {
$userType = Auth::user()->type;
if ($userType == 'admin') {
return redirect('/admin');
} else if ($userType == 'employee') {
return redirect('/employee');
} else if ($userType == 'visitor') {
return redirect('/visitor');
}
}
return $next($request);
}
Laravel too, has leave out a blank authenticated method which you can fill out on \App\Http\Controllers\Auth\LoginController which is inherited from Illuminate\Foundation\Auth\AuthenticatesUsers trait
/**
* The user has been authenticated.
*
* #param \Illuminate\Http\Request $request
* #param mixed $user
* #return mixed
*/
protected function authenticated(Request $request, $user)
{
$userType = $user->type;
if ($userType == 'admin') {
return redirect('/admin');
} else if ($userType == 'employee') {
return redirect('/employee');
} else if ($userType == 'visitor') {
return redirect('/visitor');
}
}

Resources