Laravel policy return unauthorized - php

I am trying to implement policies in my project. All tries have proven unsuccessful despite following documentation to the letter. And also read numerous posts on SO about it and other media. I did as described in docs, but nonetheless it doesn't work. What gives?
In AuthServiceProvider:
<?php
namespace App\Providers;
use App\User;
use App\Job;
use App\Policies\JobPolicy;
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
use Illuminate\Support\Facades\Gate;
class AuthServiceProvider extends ServiceProvider
{
/**
* The policy mappings for the application.
*
* #var array
*/
protected $policies = [
'App\Job' => 'App\Policies\JobPolicy',
//Job::class => JobPolicy::class,
];
/**
* Register any authentication / authorization services.
*
* #return void
*/
public function boot()
{
$this->registerPolicies();
//
}
}
In policy:
<?php
namespace App\Policies;
use App\Job;
use App\User;
use Illuminate\Auth\Access\HandlesAuthorization;
class JobPolicy
{
use HandlesAuthorization;
/**
* Determine whether the user can view any jobs.
*
* #param \App\User $user
* #return mixed
*/
public function viewAny(User $user,Job $job)
{
//return (($user->isAdmin() || $user->isModerator() || $user->isUser()) && $user->status==1);
//return ($user->isMod());
return true;
}
In controller:
public function index()
{
$this->authorize('viewAny', User::class, Job::class);
return view("jobs.index");
}
My User model:
<?php
namespace App;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use App\Role;
class User extends Authenticatable
{
use Notifiable;
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $fillable = [
'name', 'email', 'password',"role_id"
];
/**
* The attributes that should be hidden for arrays.
*
* #var array
*/
protected $hidden = [
'password', 'remember_token',
];
/**
* The attributes that should be cast to native types.
*
* #var array
*/
protected $casts = [
'email_verified_at' => 'datetime',
];
public function role(){
return $this->belongsTo("App\Role", "role_id");
}
public function isMod()
{
$user = User::find(auth()->user()->id);
$role = $user->role()->first()->name;
if($role==="job board moderator"){
return true;
}
else{
return false;
}
}
}
And Job model:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
use App\User;
class Job extends Model
{
protected $fillable = [
"title", "description", "email"
];
public function user(){
return $this->belongsTo("App\User","user_id");
}
}

In policy:
public function viewAny(User $user)
{
return true;
}
In controller:
public function index()
{
$this->authorize('viewAny', Job::class);
return view("jobs.index");
}

The way to call a model policy method changes depending on the number of parameters it has.
No object
/* In policy*/
public function viewAny(User $user)
/* In controller */
$this->authorize('viewAny', Job::class)`
1 object
/* In policy*/
public function view(User $user, Job $job)
/* In controller */
$this->authorize('view', $job)
More than 1 object
/* In policy*/
public function view(User $user, Job $job, AnotherModel $model)
/* In controller */
$this->authorize('view', [$job, $model])
Source: https://laravel.com/docs/5.8/authorization#creating-policies

Related

db:seed can't find factory() method

I'm trying to seed two tables with the following code:
<?php
namespace Database\Seeders;
// use Illuminate\Database\Console\Seeds\WithoutModelEvents;
use Illuminate\Database\Seeder;
use Illuminate\Foundation\Auth\User;
use App\Models\Role;
class DatabaseSeeder extends Seeder
{
/**
* Seed the application's database.
*
* #return void
*/
public function run()
{
User::factory(10)->create();
$roles = [
'dps',
'tank',
'healer'
];
foreach ($roles as $role) {
Role::create([
'name' => $role,
]);
}
foreach(User::all() as $user) {
foreach (Role::all() as $role) {
$user->$roles()->attach($role->id);
}
}
}
}
using php artisan db:seed, but its returning Call to undefined method Illuminate\Foundation\Auth\User::factory().
Going through User model, I have the following:
<?php
namespace App\Models;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Laravel\Fortify\TwoFactorAuthenticatable;
use Laravel\Jetstream\HasProfilePhoto;
use Laravel\Sanctum\HasApiTokens;
class User extends Authenticatable
{
use HasApiTokens;
use HasFactory;
use HasProfilePhoto;
use Notifiable;
use TwoFactorAuthenticatable;
/**
* The attributes that are mass assignable.
*
* #var string[]
*/
protected $fillable = [
'name',
'email',
'password',
];
/**
* The attributes that should be hidden for serialization.
*
* #var array
*/
protected $hidden = [
'password',
'remember_token',
'two_factor_recovery_codes',
'two_factor_secret',
];
/**
* The attributes that should be cast.
*
* #var array
*/
protected $casts = [
'email_verified_at' => 'datetime',
];
/**
* The accessors to append to the model's array form.
*
* #var array
*/
protected $appends = [
'profile_photo_url',
];
public function monstros() {
return $this->hasMany('App\Models\Monstro');
}
public function arsenais() {
return $this->hasMany('App\Models\Arsenal');
}
public function itens() {
return $this->hasMany('App\Models\Item');
}
public function roles() {
return $this->belongsToMany(Role::class);
}
}
Where we can clearly see it's calling for the Factory method with use HasFactory
What am I missing here?
Also tried to restart artisan, update the framework, dump-auto load, none of those helped.
You are calling the wrong class instead of calling the App\Models\User you are calling the Illuminate\Foundation\Auth\User. Which has the same name. You can take a look at the namespaces above.

Access restriction for users that are not admin and landlord

I am working on a laravel project. I want to restrict the api/property/create route so that only admins and landlord users can create property.However i am meeting a challenge in implementing this functionality.
Here is my route to create property
Route::group(['middleware' => ['auth:api', 'adminLandlord']], function() {
Route::post('/property/create', 'App\Http\Controllers\PropertyController#create')->name('createProperty');
});
Below is my AccountType Model
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class AccountType extends Model
{
use HasFactory;
protected $name = [
1 => 'Admin',
2 => 'Landlord',
3 => 'Guest',
4 => 'Tenant',
5 => 'Service Provider',
];
const ADMIN = 1;
const LANDLORD = 2;
const GUEST = 3;
const TENANT = 4;
const SERVICEPROVIDER = 5;
public static function getAccountName($id) {
$name = [
1 => 'Admin',
2 => 'Landlord',
3 => 'Guest',
4 => 'Tenant',
5 => 'Service Provider',
];
return $name[$id];
}
public function user()
{
return $this->hasMany(User::class);
}
}
This is the User model
<?php
namespace App\Models;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Laravel\Passport\HasApiTokens;
class User extends Authenticatable
{
use HasFactory, Notifiable, HasApiTokens;
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $fillable = [
'first_name',
'last_name',
'account_type',
'email',
'password',
'phone_number'
];
/**
* The attributes that should be hidden for arrays.
*
* #var array
*/
protected $hidden = [
'password',
'remember_token',
];
/**
* The attributes that should be cast to native types.
*
* #var array
*/
protected $casts = [
'email_verified_at' => 'datetime',
];
const ADMIN = 'Admin';
const LANDLORD = 'Landlord';
const GUEST = 'Guest';
const TENANT = 'Tenant';
const SERVICEPROVIDER = 'Service Provider';
// Get property(s) under a user
public function properties()
{
return $this->hasMany(Property::class);
}
public function roles()
{
return $this->hasOne(AccountType::class);
}
public function isAdmin()
{
return $this->account_type == 1; // this looks for an account_type column in the users table
}
public function isLandlord()
{
return $this->account_type;
}
public function isGuest()
{
return $this->account_type;
}
public function isTenant()
{
return $this->account_type;
}
public function isServiceProvider()
{
return $this->account_type;
}
}
Here is my adminLandlord middleware
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Contracts\Auth\Guard;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use App\Models\User;
use App\Models\AccountType;
class AdminLandlordMiddleware
{
/**
* The Guard implementation.
*
* #var Guard
*/
// protected $auth;
/**
* Create a new filter instance.
*
* #param Guard $auth
* #return void
*/
// public function __construct(Guard $auth)
// {
// $this->auth = $auth;
// }
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle(Request $request, Closure $next)
{
if(Auth::check() && !Auth::user()->isLandlord($this->getAccountTypeId('Landlord')) || !Auth::user()->isAdmin($this->getAccountTypeId('Admin'))){
// return $next($request);
return response()->json(['error_message' => 'Unauthorized action'], 403);
}
return $next($request);
}
public function getAccountTypeId($name)
{
$accountType = AccountType::where('name', $name)->first();
return $accountType->id;
}
}
I need to be able to pass the getAccountTypeId() to the isAdmin and isLandlord methods so as to get the accountTypeId which i will then use in the condition in the middleware. I tried it the way shown above but its not working out.
Thank you for the help.

Call to undefined method App\User::admin() error in Session in Laravel

I'm trying to put some sessions in my project and it's working fine when I'm logged out. But when I'm logged in as an Admin I'm getting the following error:
Call to undefined method App\User::admin()
this is my routes
Route::resource('/create','PagesController#showCreate')->middleware(IsAdmin::class);
Route::get('/users','UserController#index')->middleware(IsAdmin::class);
Route::get('/verify','UserController#userVerify')->middleware(IsAdmin::class);
this is my User model
<?php
namespace App;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
class User extends Authenticatable
{
use Notifiable;
/**
* The attributes that are mass assignable.
* protected $table = 'users';
*public $primaryKey ='id';
* #var array
*/
protected $fillable = [
'name', 'email', 'password','userType',
];
/**
* The attributes that should be hidden for arrays.
*
* #var array
*/
protected $hidden = [
'password', 'remember_token',
];
/**
* The attributes that should be cast to native types.
*
* #var array
*/
protected $casts = [
'email_verified_at' => 'datetime',
'admin' => 'boolean',
];
public function posts(){
return $this->hasMany('App\Post');
}
public function isAdmin()
{
return $this->admin;
}
}
and this is my IsAdmin class
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Support\Facades\Auth;
class IsAdmin
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle($request, Closure $next)
{
{
if ( Auth::check() && Auth::user()->admin() )
{
return $next($request);
}
return redirect('home');
}
}
}
And every time I try to redirect to other routes I get the same error except for the dashboard
Change if statement in your IsAdmin class:
if ( Auth::check() && Auth::user()->isAdmin() )

where is the attribute in the laravel code comes from?

<?php
namespace App\Models;
use Illuminate\Auth\Authenticatable;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Auth\Passwords\CanResetPassword;
use Illuminate\Foundation\Auth\Access\Authorizable;
use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract;
use Illuminate\Contracts\Auth\Access\Authorizable as AuthorizableContract;
use Illuminate\Contracts\Auth\CanResetPassword as CanResetPasswordContract;
class User extends Model implements AuthenticatableContract,
AuthorizableContract,
CanResetPasswordContract
{
use Authenticatable, Authorizable, CanResetPassword;
/**
* The database table used by the model.
*
* #var string
*/
protected $table = 'users';
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $fillable = ['name', 'email', 'password'];
/**
* The attributes excluded from the model's JSON form.
*
* #var array
*/
protected $hidden = ['password', 'remember_token'];
public static function boot()
{
parent::boot();
static::creating(function ($user) {
$user->activation_token = str_random(30);
});
}
public function gravatar($size = '100')
{
$hash = md5(strtolower(trim($this->attributes['email'])));
return "http://www.gravatar.com/avatar/$hash?s=$size";
}
public function statuses()
{
return $this->hasMany(Status::class);
}
public function feed()
{
return $this->statuses()->orderBy('created_at', 'desc');
}
public function followers()
{
return $this->belongsToMany(User::Class, 'followers', 'user_id', 'follower_id');
}
public function followings()
{
return $this->belongsToMany(User::Class, 'followers', 'follower_id', 'user_id');
}
public function follow($user_ids)
{
if (!is_array($user_ids)) {
$user_ids = compact('user_ids');
}
$this->followings()->sync($user_ids, false);
}
public function unfollow($user_ids)
{
if (!is_array($user_ids)) {
$user_ids = compact('user_ids');
}
$this->followings()->detach($user_ids);
}
public function isFollowing($user_id)
{
var_dump($this->followings);die();
return $this->followings->contains($user_id);
}
}
This is a code come from laravel models.
There is a method named $this->followings() .But I don't see any $this->followings attribute assigned in the code.
where is the $this->followings comes from?
thanks
Suggested reading about Laravel model relationships
in particular:
Once the relationship is defined, we may retrieve the related record using Eloquent's dynamic properties. Dynamic properties allow you to access relationship methods as if they were properties defined on the model

Laravel 5 - Laracast Easy Auth - Saving an article

I was following a tutorial on laracast about easy auth (Easy Auth), but there were some gaps on the video, i had to declare
use Auth;
to be able to get the current user, however, when i save the article i get this error
FatalErrorException in ArticleController.php line 42:
Call to undefined method Illuminate\Database\Eloquent\Collection::save()
where the corresponding code in my ArticleController is
public function store(ArticleRequest $request)
{
$article = new Article($request->all());
Auth::user()->articles->save($article);
return redirect('blog');
}
My Article model:
<?php namespace App;
use Illuminate\Database\Eloquent\Model;
use Carbon\Carbon;
class Article extends Model {
protected $fillable = [
'title',
'body',
'published_at',
'user_id'
];
protected $dates = ['published_at'];
public function scopePublished ($query)
{
$query->where('published_at', '<=', Carbon::now());
}
public function scopeUnpublished ($query)
{
$query->where('published_at', '>', Carbon::now());
}
public function setPublishedAtAttribute($date)
{
$this->attributes['published_at'] = Carbon::parse($date);
}
public function user()
{
return $this-> belongsTo('App\User');
}
}
My User model
<?php namespace App;
use Illuminate\Auth\Authenticatable;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Auth\Passwords\CanResetPassword;
use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract;
use Illuminate\Contracts\Auth\CanResetPassword as CanResetPasswordContract;
class User extends Model implements AuthenticatableContract, CanResetPasswordContract {
use Authenticatable, CanResetPassword;
/**
* The database table used by the model.
*
* #var string
*/
protected $table = 'users';
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $fillable = ['name', 'email', 'password'];
/**
* The attributes excluded from the model's JSON form.
*
* #var array
*/
protected $hidden = ['password', 'remember_token'];
public function articles()
{
return $this-> hasMany('App\Article');
}
}
try with this
Auth::user()->articles()->save($article);
store action
public function store(ArticleRequest $request)
{
$article = new Article($request->all());
Auth::user()->articles()->save($article);
return redirect('blog');
}

Categories