Restrict page if Auth::user()->id != user_id using middleware - laravel

i use middleware to restrict the admin page from non-admins, and i can restrict pages with a list of "patients" from other users by using a policy, but if i use a policy. I have to repeat the code can() method in every function. If i use middleware to check if the user_id in the url == Auth::user()->id. I do not need to repeat this, but how do i get the user_id from the url in my middleware?
the route
Route::get('/patients/{patient}', 'PatientController#edit')
What i have now
PatientPolicy
public function view(User $user, Patient $patient)
{
// does this patient belong to user
return $user->id == $patient->user_id;
}
PatientController
public function edit(Patient $patient)
{
// authenticate logged in user
$user = auth()->user();
// can the loged in user do this?(policy)
if($user->can('update', $patient)){
return view('patient.edit-patient', compact('patient', 'user'));
}
return view('403');
}
what i should have in a middleware
UserMiddleware
/**
* #param $request
* #param Closure $next
* #return mixed
*/
public static function handle($request, Closure $next)
{
if (Auth::check() && Auth::user()->id == User::patients()->user_id) {
return $next($request);
} else {
return redirect()->route('login');
}
}
Does somebody know how to check if the {patient} in the routes user_id == the logged in user()->id?

Since you have Illuminate\Http\Request object injected into handle function in middleware this is pretty straight forward to get patient id from url:
/**
* #param $request
* #param Closure $next
* #return mixed
*/
public static function handle($request, Closure $next)
{
$patientId = $request->patient; // patient id from url!
$patient = Patient::find($patientId);
if (!$patient) {
return redirect()->back()->with(['message' => 'Patient not found!']);
}
if (Auth::check() && (int) Auth::user()->id === (int) $patient->id) {
return $next($request);
} else {
return redirect()->route('login');
}
}

Thank you #Leorent,
Your answer helped me alot and this is how it got fixed
Route
Route::get('/patients/{patient}', 'PatientController#show')->middleware('user');
UserMiddeware
public static function handle($request, Closure $next)
{
$patientId = $request->patient->user_id; // user_id from patient in url!
if (Auth::check() && (int) Auth::user()->id == $patientId) {
return $next($request);
} else {
return redirect()->route('403');
}
}
Thanks again!

Related

How to create middleware correctly?

Good day. I need to create a check, the id of the authorized user matches the entry from the user_id database. Help me please
Middleware CanEdit.php
<?php
namespace App\Http\Middleware;
use App\Models\Pass;
use Closure;
use Auth;
use Illuminate\Http\Request;
class CanEdit
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle($request, Closure $next)
{
$user = Auth::user()->id;
$editor = Pass::where('user_id', $user);
if ($user == $editor) {
return $next($request);
}
return redirect('home')->with('error','You have not access');
}
}
You're never getting in the if condition because you're comparing two different classes here. If you need to check if only id's match, you could do it like this:
$user = Auth::user()->id;
$editor = Pass::where('user_id', $user)->first();
if ($user == $editor->user_id) {
return $next($request);
}
But in my opinion, this check is not necessary. Assuming that user_id field is unique in Pass table, you don't need to check if id's match, you only need to check if record exists in Pass table:
$user = Auth::user()->id;
$editor = Pass::where('user_id', $user)->exists();
if ($editor) {
return $next($request);
}
exists() method simply returns boolean depending on if the record exists in the database or not.
if (Auth::guard($guard)->guest()) {
if ($request->ajax() || $request->wantsJson()) {
return response('Unauthorized.', 401);
} else {
return redirect()->guest('login');
}
}
return $next($request);

Block the access to a page students.index()

In my navbar I have 2 pages which are Student Add and Student Index.
When I click on Student Add, I have an error message Access Denied.
Great, no problem...
Now, I would like to make the even thing with the page Students Index and display the items, I have a problem.
I have access to the content...
In my Controller Student I have this:
class StudentController extends Controller
{
public function __construct()
{
$this->middleware(['auth', 'clearance'])
->except('index', 'show');
}
/**
* Display a listing of the resource.
*
* #return \Illuminate\Http\Response
*/
public function index()
{
$students = Student::orderby('id', 'desc')->paginate(5);
return view('students.index', compact('students'));
}
/**
* Show the form for creating a new resource.
*
* #return \Illuminate\Http\Response
*/
public function create()
{
return view('students.create');
}
/**
* Store a newly created resource in storage.
*
* #param \Illuminate\Http\Request $request
* #return \Illuminate\Http\Response
*/
public function store(Request $request)
{
$this->validate($request, [
'name'=>'required',
'firstname' =>'required',
]);
$name = $request['name'];
$firstname = $request['firstname'];
$student = Student::create($request->only('name', 'firstname'));
return redirect()->route('students.index')
->with('flash_message', 'Article,
'. $student->name.' created');
}
Then, in my Class ClearanceMiddleware I have this:
public function handle($request, Closure $next) {
if (Auth::user()->hasPermissionTo('Administer roles & permissions')) {
return $next($request);
}
if ($request->is('students/create')) {
if (!Auth::user()->hasPermissionTo('Create Student')) {
abort('401');
} else {
return $next($request);
}
}
if ($request->is('students/index')) {
if (!Auth::user()->hasPermissionTo('Index Student')) {
abort('401');
} else {
return $next($request);
}
}
I don't see the missed step. I have to block the access please.
2 things:
1) You need to adjust the middleware call in your controller's constructor. The except() method means the middleware will not run on those methods, so if you want the middleware to run on the index method, you will need to remove it from except().
This will call the middleware on every route method except show():
$this->middleware(['auth', 'clearance'])
->except('show');
2) Inside your middleware, you are using $request->is() to match on the path, but the url for index is not 'students/index'.
// The url path for the index route is '/students'
if ($request->is('students')) {
if (!Auth::user()->hasPermissionTo('Index Student')) {
abort('401');
} else {
return $next($request);
}
}
$this->middleware(['auth', 'clearance'])
->except('show');
Remove index from the except method. As it is you are exempting the index method from the middleware check.

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');
}
}

How to add conditions in laravel auth

I am using Laravel 5.8.
I want to add email_verified_at != null OR phone_number_verified_at != null in auth.
How do I do that?
Use this in web.php route Auth::routes(['verify' => true]);
Read this link https://laravel.com/docs/5.8/verification#verification-routing
if you are using this its check email verified or not Auth::routes(['verify' => true]);
If you want to more about go to this path in laravel project \vendor\laravel\framework\src\Illuminate\Auth and see trait MustVerifyEmail
public function hasVerifiedEmail()
{
return ! is_null($this->email_verified_at);
}
You are trying to check both
overite one method
public function hasVerifiedEmail()
{
if (!is_null($this->phone_verified_at) && !is_null($this->email_verified_at)) {
return 1;
}
}
2.step go to VerificationController
/**
* Show the email verification notice.
*
* #param \Illuminate\Http\Request $request
* #return \Illuminate\Http\Response
*/
public function show(Request $request)
{
$user = Auth::user();
if (is_null($user->email_verified_at)) {
return view('auth.verify');
}elseif (is_null($user->phone_verified_at)) {
return redirect("phone_verify");
}else{
return redirect($this->redirectPath());
}
}
go to web.php create route for phone verify
Route::get('phone_verify',function(){
dd("not verify");
});
Add attemptLogin function in LoginController, this function is called by laravel to authenticate
protected function attemptLogin(Request $request)
{
$valid = $this->guard()->attempt(
$this->credentials($request), $request->filled('remember')
);
if($valid){
$user = $this->guard()->user();
if($user->email_verified_at == null && $user->phone_number_verified_at == null ){
$this->guard()->logout();
$request->session()->invalidate();
return false;
}
}
return true;
}

In a middleware, how can I get current logged in user?

I am creating a middleware that checks if user is currently logged in and is super admin.
This is my middleware code.
namespace App\Http\Middleware;
use Closure;
use Illuminate\Support\Facades\Auth;
class CheckAdmin
{
/**
* 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()) {
// also need to check a field of user
return redirect()->guest('login');
} else {
return $next($request);
}
}
}
Actually, it's the same as the default middleware Authenticate (i.e. 'auth')
It's working well when I use it in app's routing. (app/Http/routes.php)
I need to use it with cuddy plugin middleware option. It should redirects only guest users, but it's not. Please help!
Authenticate middleware by default checks if user is guest and redirects him to login page see below
if (Auth::guard($guard)->guest()) {
if ($request->ajax() || $request->wantsJson()) {
return response('Unauthorized.', 401); //if ajax request
} else {
return redirect()->guest('login'); //redirect
}
}
Now if u want to check if user is logged and check some user fields here how it should be
public function handle($request, Closure $next, $guard = null)
{
if(Auth::check()) { //If is logged in
$user = Auth::user();
if($user->isSuperAdmin())
return $next($request);
}
return redirect('/whatever');
}
If you attach 'auth' middleware + this custom middleware. You can get rid of "Auth::check()" in the custom middleware.
Route::group(['middleware' => ['web', 'auth', 'custom']], function () {
Route::get('/url/only/for/super/users', 'Whatever#whateverController');
});
public function handle($request, Closure $next, $guard = null)
{
$user = Auth::user();
if($user->isSuperAdmin())
return $next($request);
return redirect('/whatever');
}
There is many helper functions in laravel that you can use anywhere like auth() helper, see helpers. So you can use this code anywhere:
auth()->user();

Resources