Laravel 8 returns 403 UNAUTHORIZED ACCESS - php

I'm working with Laravel 8, and I have a resource Controller named Profile. And within this Controller, users can edit their user profile information.
So at the edit method, I put this:
public function edit(User $user)
{
$this->authorize('edit-user', $user);
return view('editprofile', compact('user'));
}
And users can access editprofile blade by this button:
Edit Profile
But now the problem is, it returns this:
403 THIS ACTION IS UNAUTHORIZED.
However I am already logged in and I want to access my own profile.edit and not other users!
So if you know why am I getting this error, please let me know, I would really appreciate any idea or suggestion from you guys...
Thanks.
And here is also my route:
Route::middleware('auth')->group(function() {
Route::resource('profile' , ProfileController::class);
});
UDPATE 1:

Please change the followings
Route parameter names is "profile"
So, the controller method parameter must be the same "$profile".
public function edit (Request $request, User $profile) {
Gate::allows('edit-user', $profile);
// do the logic
}

i had the same error. i changed
public function authorize()
{
return false;
}
to
public function authorize()
{
return true;
}
in App\Http\Requests\StoreProductRequest

Related

Laravel how to customize user profile url based on currently logged in user

I have created a IndexController.php class which handles user related data control.
So I can get the currently logged in user from following method. but the url is kind of universal url. I want it to be custom url based on the logged in user. for ex If userx logged in as the user, his profile should display as http://127.0.0.1:8000/user/userx. How do i fix this?
IndexController.php
class IndexController extends Controller{
public function Index(){
return view('dashboard.index');
}
public function userLogout(){
Auth::logout();
return Redirect()->route('login');
}
public function userProfile(){
$id = Auth::user()->id;
$user = User::find($id);
return view('dashboard.profile',compact('user'));
}
}
Web.php
Route::get('/user/profile',[IndexController::class, 'userProfile'])->name('user.profile');
Create a route with a parameter, then fetch the profile using that variable:
Route::get('/user/profile/{username}',[IndexController::class, 'userProfile'])->name('user.profile');
Then in your controller, you should have access to this username in the method arguments:
public function userProfile(Request $request, $username)
{
$user = User::query()->where('username', $username)->firstOrFail();
// ...
}
If you then want to add extra functionality for when you are on your own profile page (like changing password etc), you'd have to check the authenticated user Auth::user(). Alternatively, you can keep the default /user/profile route as the URL to visit when you want to change your own profile. There are multiple ways to solve this :)
You need to check two Laravel concepts:
Route Model Binding
Named route
Route
Route::get('/user/{profile}',[IndexController::class, 'userProfile'])->name('user.profile');
Controller
public function userProfile(User $profile){
// Check if $profile is the same as Auth::user()
// If only the user can see his own profile
$id = Auth::user()->id;
$user = User::find($id);
return view('dashboard.profile',compact('user'));
}
Blade
See profile
Or
See profile

Laravel route resolving to a different method

I'm trying to set up a basic Laravel CRUD application, and I'm getting stuck setting up the pages for each action.
When I visit the route case/create, it opens the page for show instead.
routes/web.php
use App\Http\Controllers\HospitalCase as HospitalCase;
Route::controller(HospitalCase::class)->group(function() {
Route::get('/cases','index')->middleware('auth')->name('cases');
Route::get('/case/{id}','show')->middleware('auth');
Route::get('/case/create','create')->middleware('auth');
Route::post('/case/create','store')->middleware('auth');
Route::get('/case/edit/{$id}','edit')->middleware('auth');
Route::post('/case/edit/{$id}','update')->middleware('auth');
Route::get('/case/delete/{$id}','destroy')->middleware('auth');
});
HospitalCase.php controller
class HospitalCase extends Controller
{
function index()
{
echo 'index';
}
function create()
{
echo 'create';
}
function show($id)
{
echo 'show';
}
function store()
{
// validation rules
}
function edit($id)
{
return view('case/edit');
}
function update($id)
{
}
function destroy($id)
{
}
}
This is what I see on the browser:
I have been trying to figure this out for hours and can't think of what I'm doing wrong.
PS: The auth middleware is using laravel breeze (unmodified)
The reason it's showing the show route is because you defined
Route::get('/case/{id}','show')->middleware('auth');
before it, therefore, it's matching case/create as show('create')
Try defining the route afterwards.
Route::get('/case/create','create')->middleware('auth');
Route::post('/case/create','store')->middleware('auth');
Route::get('/case/{id}','show')->middleware('auth');
Just want to reiterate what #TimLewis has suggested, I think you need to put this route:
Route::get('/case/create','create')->middleware('auth');
Above this route:
Route::get('/case/{id}','show')->middleware('auth');
But you could try using Laravel’s route resource so you don’t need to write out all the routes -
use App\Http\Controllers\HospitalCaseController;
Route::resource('case', HospitalCaseController::class);

Laravel 8: Call to undefined method Model::contains()

I'm using Laravel 8 for my project and in this project and I have created a custom Middleware called Admin that goes like this:
public function handle(Request $request, Closure $next)
{
if (Auth::user()->isAdmin()) {
return $next($request);
}
return redirect('/');
}
And I tried applying it like this:
Route::middleware('admin')->group(function () {
Route::get('test', function () { return "User is authenticated and is an admin."; });
});
And on Kernel.php at $middlewareGroups section:
'admin' => [
'auth',
\App\Http\Middleware\Admin::class
],
So I called the isAdmin() at User Model which simply checks if the role of the user is correct or not:
public function role()
{
return $this->belongsTo(Role::class);
}
public function isAdmin()
{
return $this->role->contains('slug', 'super-admin');
}
But now the problem is, when I go to /test uri, it does not redirect me to ('/') uri and shows me this error:
BadMethodCallException
Call to undefined method App\Models\Role::contains()
So what is going wrong here? How can I fix this issue?
Note that the relationship between roles and users table is One To Many. That's why I wrote role() instead of roles() because each user has only one role.
When you use a belongsTo relationship, laravel will return the model directly and not a collection of models.
When you call:
$this->role
What you get is either null (if the relationship does not exist) or a Role model. You can write your isAdmin function accordingly:
public function isAdmin()
{
return empty($this->role) ? false : $this->role->slug === 'super-admin';
}
You probably copied the code from an example with a Many to many relationship: in that case Laravel will return a collection of models and you can invoke collection methods on it, such as contains
could we see a snip of your Role Model.

Laravel Gate for authorization check

I used Gate for laravel authorization where A user have One role and one role have Multiple Permissions. I used the following method for checking role has permission or not. But it doesn't work properly means user may have chance to access one route though I have given him multiple permissions through roles.
See the scenario is suppose admin can see list of users as well can access test route. But in my case admin can see list of users but he can't access the test route. Though I have given him the access in permission table.
Can anyone suggest what's the problem here?
public function boot(GateContract $gate)
{
$this->registerPolicies();
foreach ($this->getPermissions() as $permission) {
$gate->define($permission->name, function ($user) use ($permission) {
return $user->role->id === $permission->role_id;
});
}
}
public function getPermissions()
{
return Permission::with('role')->get();
}
In controller Code :
public function test(){
if(Gate::allows('test')){
echo "This is Test";
}
return redirect('/');
}

Laravel 5 form request validation with ID - show

I am wanting to validate a resource controller in Laravel, so that the user can only access clinic.show if they're the owner of said clinic.
I correctly validated this using the following:
public function show($id)
{
if (Clinic::where('id', $id)->where('user_id', Auth::id())->exists()) {
return View::make('clinic.show', ['clinic' => Clinic::where('id', $id)
->first()]);
} else {
abort(401, 'Unauthorized action.');
}
}
However, I believe this is bad practice and I should be using the Form Request feature within Laravel.
I have created a ShowClinicFormRequest.php and added the following code:
public function authorize()
{
$clinicId = $this->route('clinic');
return Clinic::where('id', $clinicId)
->where('user_id', Auth::id())
->exists();
}
And within the show function -
public function show($id, ShowClinicFormRequest $request)
{
return View::make('clinic.show', ['clinic' => Clinic::where('id', $id)->first()]);
}
However, the error that I am getting is:
ReflectionException in RouteDependencyResolverTrait.php line 53: Class
App\Http\Controllers\ShowClinicFormRequest does not exist
It obviously doesn't exist within that directory because it isn't a controller.
Any help would be greatly appreciated.
I believe your form request is located in the App\Http\Requests namespace so you need to import the class or use explicitly:
use App\Http\Requests\ShowClinicFormRequest;
or just
public function show($id, \App\Http\Requests\ShowClinicFormRequest $request)
{}
You might also to take a look at filters or middlewares.

Categories