Laravel authorization/policy prevents access for everyone - laravel

I found similar title and similar asked question on this website when I was researching to solve the problem. But none of posted answers helped me. This question might be duplicated but I could not solve the problem using existing questions on StackOverflow.
I'm trying to prevent access to users who are not logged in OR who are not member of "School" model!
In "web.php" file I used "middleware("auth")" to prevent access to users who are not logged in.
Now I created a "Policy" named "SchoolPolicy" to prevent access to users who are not member of "Schools" database/model.
When I call "view" method from SchoolPolicy, it prevents access for all authorized and unauthorized users!
I also checked and I realized "School" model returns "null" when I try to catch "user_id" foreign key from "schools" table.
The below piece of code is the way I created "Schools" table using Migration:
Schema::create('schools', function (Blueprint $table) {
$table->id();
$table->foreignId('user_id')->constrained();
$table->string('school_name');
$table->string('school_address')->nullable();
$table->string('school_email');
$table->string('school_phone')->nullable();
$table->string('url');
$table->longText('descriptions')->nullable();
$table->timestamps();
});
This is the route to view any school which is created by any user (URL can be dynamic)
Route::group(['middleware' => 'auth'], function () {
Route::get('/schools/{url}', [ViewSchool::class, 'index'])->name('yourschool.show');
});
And this is "School" model. I used php artisan make:model School command to create this model:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Support\Facades\Auth;
class School extends Model{
use HasFactory;
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $fillable = [
'user_id',
'school_name',
'school_address',
'school_email',
'school_phone',
'url',
'descriptions'
];
}
In this section I created School Policy. However I used Laravel 8 but I also registered created Policy manually
SchoolPolicy
<?php
namespace App\Policies;
use App\Models\School;
use App\Models\User;
use Illuminate\Auth\Access\HandlesAuthorization;
class SchoolPolicy
{
use HandlesAuthorization;
/**
* Determine whether the user can view any models.
*
* #param \App\Models\User $user
* #return mixed
*/
public function viewAny(User $user)
{
//
}
/**
* Determine whether the user can view the model.
*
* #param \App\Models\User $user
* #param \App\Models\School $school
* #return mixed
*/
public function view(User $user, School $school)
{
return $user->id == $school->user_id;
}
}
In AuthServiceProvider.php I registered SchoolPolicy like this:
<?php
namespace App\Providers;
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
use Illuminate\Support\Facades\Gate;
use App\Models\User;
use App\Models\School;
use App\Policies\SchoolPolicy;
class AuthServiceProvider extends ServiceProvider
{
/**
* The policy mappings for the application.
*
* #var array
*/
protected $policies = [
School::class => SchoolPolicy::class
];
/**
* Register any authentication / authorization services.
*
* #return void
*/
public function boot()
{
$this->registerPolicies();
}
}
"ViewSchool.php" file where I want to use authorize method:
<?php
namespace App\Http\Controllers\Schools;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use App\Models\User;
use App\Models\School;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Auth;
class ViewSchool extends Controller
{
public function index (School $school) {
$this->authorize('view', $school);
return view('layouts.viewschool');
}
}
I tried many ways to solve the problem, but none of them properly worked:
First Try:
public function index (School $school) {
$this->authorize('view', $school);
}
Second Try:
public function index () {
$this->authorize('view', School::class);
}
I even tried to print any output from School model but I receive "null":
public function index (School $school) {
dd($school->user_id);
}
I followed all tutorials on YouTube and official Laravel website, but in my examples I gave you, authorization doesn't work properly.
Please help me to solve this problem.
Thank you

Related

Why won't artisan allow me to create data from my model?

I'm rather new to Laravel and am currently running Laravel 8.x on Windows 10. I've created a database table, model, factory and seeder for generating articles for an imaginary blog. (I'm imitating a tutorial on Laravel and Vue that I like on YouTube and also this article).
The article suggests verifying that everything works by going into php artisan tinker and executing the command:
Article::factory()->create();
When I do that, I get this message:
PHP Fatal Error: Class 'Article' not found in Psy Shell code on line 1
I have no idea what that's supposed to mean but I assume it's not happy with my code in some respect. I've looked at it as thoroughly as I can but don't see anything wrong based on the examples in the article. Could someone more knowledgeable in Laravel kindly eyeball this and tell me what I've done wrong? (For what it's worth, I tried User::factory()->create(); and it worked fine.)
Article.php is stored in app/Models and contains:
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Article extends Model
{
use HasFactory;
protected $fillable = [
'title', 'body',
];
}
ArticleFactory.php is stored at database/factories and contains:
<?php
namespace Database\Factories;
use App\Models\Article;
use Illuminate\Database\Eloquent\Factories\Factory;
use Illuminate\Support\Str;
class ArticleFactory extends Factory
{
/**
* The name of the factory's corresponding model.
*
* #var string
*/
protected $model = Article::class;
/**
* Define the model's default state.
*
* #return array
*/
public function definition()
{
return [
'title' => $this->faker->text(50),
'body' => $this->faker->text(200)
];
}
}
2020_11_30_034856_create_articles_table is stored at database/migrations and contains:
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class CreateArticlesTable extends Migration
{
/**
* Run the migrations.
*
* #return void
*/
public function up()
{
Schema::create('articles', function (Blueprint $table) {
$table->id();
$table->string('title');
$table->text('body');
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* #return void
*/
public function down()
{
Schema::dropIfExists('articles');
}
}
Lastly, ArticlesTableSeeder.php is stored at database/seeders and contains:
<?php
namespace Database\Seeders;
use Illuminate\Database\Seeder;
class ArticlesTableSeeder extends Seeder
{
/**
* Run the database seeds.
*
* #return void
*/
public function run()
{
Article::factory()
->times(30)
->create();
}
}
Can anyone see why this code isn't working?
EDIT:
I tried Patricus' suggestion and it worked fine in tinker. However, when I tried php artisan db:seed, it failed. I got this error:
Seeding: Database\Seeders\ArticlesTableSeeder
Error
Class 'Database\Seeders\Article' not found
at C:\Laravel\larticles\database\seeders\ArticlesTableSeeder.php:16
12▕ * #return void
13▕ */
14▕ public function run()
15▕ {
➜ 16▕ Article::factory()
17▕ ->times(30)
18▕ ->create();
19▕ }
20▕ }
1 C:\Laravel\larticles\vendor\laravel\framework\src\Illuminate\Container\BoundMethod.php:36
Database\Seeders\ArticlesTableSeeder::run()
2 C:\Laravel\larticles\vendor\laravel\framework\src\Illuminate\Container\Util.php:40
Illuminate\Container\BoundMethod::Illuminate\Container\{closure}()
Tinker doesn't run in a namespace. While it tries to help you out with some things related to models, it can't autocorrect namespaces on static method calls.
Your model is \App\Models\Article. In tinker, you need to call:
\App\Models\Article::factory()->create();

Laravel Showing all users and check if belong to Bans table

Hi im working on admin dashboard
and i want to show all users and check if the user blocked get information about the ban from bans table
im using cybercog/laravel-ban to ban users
Laravel 5.8
So i have two table
Users table and Bans table
Bans table has the user id of the banded user in column called : bannable_id
User model :
namespace App;
use Illuminate\Notifications\Notifiable;
use Cog\Contracts\Ban\Bannable as BannableContract;
use Cog\Laravel\Ban\Traits\Bannable;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Support\Facades\Auth;
use Illuminate\Auth\Events\Verified;
class User extends Authenticatable implements MustVerifyEmail,BannableContract
{
use Notifiable;
use Bannable;
protected $fillable = [
'name', 'email', 'password',
'last_login_at',
'last_login_userganet',
'avatar','uid'
];
/**
* 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 UserBan()
{
return $this->hasOne('App\Ban','bannable_id');
}
Ban Model :
namespace App;
use Illuminate\Database\Eloquent\Model;
class Ban extends Model
{
protected $fillable = [
'id','expired_at','bannable_type'
];
protected $casts = [
'bannable_type'
];
public function Users()
{
return $this->belongsTo('App\User');
}
}
User Controller :
namespace App\Http\Controllers;
use App\User;
use App\Ban;
use App\Http\Requests\UserRequest;
use Illuminate\Http\Request;
use Illuminate\Support\Str;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Hash;
use Cog\Contracts\Ban\Bannable;
class UserController extends Controller
{
/**
* Display a listing of the users
*
* #param \App\User $model
* #return \Illuminate\View\View
*/
public function index(User $model,Ban $banModel)
{
return view('users.index', ['users' => $model->paginate(15),'bans'=>$banModel->paginate(15)]);
}
Users schema :
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateUsersTable extends Migration
{
/**
* Run the migrations.
*
* #return void
*/
public function up()
{
Schema::create('users', function (Blueprint $table) {
$table->bigIncrements('id');
$table->string('name');
$table->string('email')->unique();
$table->timestamp('email_verified_at')->nullable();
$table->timestamp('last_login')->nullable();
$table->string('last_login_provider')->nullable();
$table->string('last_login_useragent')->nullable();
$table->string('last_login_ip')->nullable();
$table->string('uid')->nullable();
$table->string('password');
$table->string('avatar')->nullable();
$table->string('facebook_id')->unique()->nullable();
$table->string('google_id')->unique()->nullable();
$table->string('twitter_id')->unique()->nullable();
$table->string('instagram_id')->unique()->nullable();
$table->enum('user_type',['member','admin'])->default('member');
$table->boolean('blocked')->default(false);
$table->timestamp('banned_at')->nullable();
$table->rememberToken();
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* #return void
*/
public function down()
{
Schema::dropIfExists('users');
}
}
I could not found the bans schema but this is the table of bans :
you are using wrong relationship, you should use polymorphic. Look link below.
https://laravel.com/docs/5.8/eloquent-relationships#one-to-one-polymorphic-relations
it would be something like
User model
public function ban()
{
return $this->morphOne('App\Ban', 'bannable');
}
Ban Model
public function bannable()
{
return $this->morphTo();
}
get all users in controller
define
use App\User;
then
$users = User::all();
then you can foreach it and call ban() method on each
foreach($users as $user)
{
//return associated ban model
$user->ban;
}
Or for better performance, use
User::with(ban)->get();
which highly decrease number of SQL calls. It retrieves all user with ban model. Look at eager loading in link below.
https://laravel.com/docs/5.8/eloquent-relationships#eager-loading
Hope it helps. :)

laravel policy not called

Does documention hides something, or there is something hidden?
created with
php artisan make:policy AdvertisementPolicy --model=Advertisement
class AdvertisementPolicy
{
use HandlesAuthorization;
/**
* Determine whether the user can view any advertisements.
*
* #param \App\User $user
* #return mixed
*/
public function viewAny(User $user)
{
return false;
}
public function view(User $user, Advertisement $advertisement)
{
return false;
}
model was created with cli too
namespace App;
class Advertisement extends Model
{
Registered through:
use App\Advertisement;
use App\Policies\AdvertisementPolicy;
class AuthServiceProvider extends ServiceProvider
{
protected $policies = [
Advertisement::class => AdvertisementPolicy::class,
Is here any additional steps to fulfill this policy registration with laravel 6?
There is no something hidden in documentation. You just don't read the documentation carefully.
Please take a look at the Authorizing Actions Using Policies section.
Your policy is never called, because you don't use it anywhere in your code. Atleast, if you need to run your policy for your controller resources, you need to write something like this:
<?php
namespace App\Http\Controllers;
use App\Advertisement;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
class AdvertisementController extends Controller
{
public function __construct()
{
$this->authorizeResource(Advertisement::class, 'advertisement');
}
}

postman 404 Not Found

I'm a beginner in laravel API I want to display list of articles (method index),I already created model Article, but I can not.
Hi, I'm a beginner in laravel API I want to display list of articles (method index),I already created model Article, but I can not.
ArticleController
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Http\Requests;
use App\Article;
use App\Http\Resources\Article as ArticleResource;
class ArticleController extends Controller
{
/**
* Display a listing of the resource.
*
* #return \Illuminate\Http\Response
*/
public function index()
{
$articles= Article::paginate(15);
return ArticleResource::collection($articles);
}
create_table_articles
public function up()
{
Schema::create('articles', function (Blueprint $table) {
$table->increments('id');
$table->string('title');
$table->string('body');
$table->timestamps();
});
}
AppServiceProvider.php
<?php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
use Illuminate\Support\Facades\Schema;
class AppServiceProvider extends ServiceProvider
{
/**
* Bootstrap any application services.
*
* #return void
*/
public function boot()
{
Schema::defaultStringLength(191);
}
ArticlesTableSeeder
<?php
use Illuminate\Database\Seeder;
class ArticalesTableSeeder extends Seeder
{
/**
* Run the database seeds.
*
* #return void
*/
public function run()
{
factory(App\Article::class,30)->create();
}
}
ArticleFactory.php
<?php
/* #var $factory \Illuminate\Database\Eloquent\Factory */
use Faker\Generator as Faker;
$factory->define(App\Article::class, function (Faker $faker) {
return [
'title' => $faker->text(50),
'body' => $faker->text(200)
];
});
App\Resources\Article.php
<?php
namespace App\Http\Resources;
use Illuminate\Http\Resources\Json\JsonResource;
class Article extends JsonResource
{
/**
* Transform the resource into an array.
*
* #param \Illuminate\Http\Request $request
* #return array
*/
public function toArray($request)
{
return parent::toArray($request);
}
}
DatabaseSeeder.php
<?php
use Illuminate\Database\Seeder;
class DatabaseSeeder extends Seeder
{
/**
* Run the database seeds.
*
* #return void
*/
public function run()
{
$this->call(ArticalesTableSeeder::class);
}
}
routes/api.php
//list
Route::get('articles','ArticleController#index');
//list single
Route::get('article/{id}','ArticleController#show');
//create article
Route::post('article','ArticleController#store');
//update articles
Route::put('article','ArticleController#store');
//delete article
Route::delete('articles','ArticleController#destroy');
Laravel automatically prefixes routes in the routes/api.php file with the route prefix /api
You need to make a request to:
http://127.0.0.1:8000/api/articles
Rather than
http://127.0.0.1:8000/articles
You can change this in your RouteServiceProvider if your prefer:
https://github.com/laravel/laravel/blob/master/app/Providers/RouteServiceProvider.php#L66-L72

How to save One to Many Relationship to database

Below is my LevelOneModel. I can't seem to figure out what I have not included. Please I need assistance.
What I want to achieve is to have all the users id in the levelone table
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class LevelOneModel extends Model
{
public function users(){
return $this->hasMany('App\User');
}
}
Below is my User model
<?php
namespace App;
use Illuminate\Notifications\Notifiable;
use Illuminate\Foundation\Auth\User as Authenticatable;
class User extends Authenticatable
{
use Notifiable;
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $fillable = [
'first_name',
'last_name',
'email',
'phone',
'bank_name',
'acct_name',
'acct_number',
'profile_pix',
'sme',
'other_sme',
'password',
];
public function levelone()
{
return $this->belongsTo('App\LevelOneModel');
}
/**
* The attributes that should be hidden for arrays.
*
* #var array
*/
protected $hidden = [
'password', 'remember_token',
];
}
And below is my level one migration file
<?php
use Illuminate\Support\Facades\Schema;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Database\Migrations\Migration;
class CreateLevelOneTable extends Migration
{
/**
* Run the migrations.
*
* #return void
*/
public function up()
{
Schema::create('level_one', function (Blueprint $table) {
$table->increments('id');
$table->integer('users_id')->unsigned();
$table->integer('upline_id')->nullable();
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* #return void
*/
public function down()
{
Schema::dropIfExists('level_one');
}
}
Thanks
I notice some things in your code....
Looking at your classes, I understand the relationship is like this
a user belongs to one LevelOne only.
a LevelOne can have multiple users
If that is correct, the relationship is incorrectly build in the migration. Because you are adding a user_id to the level_one table.
It should be the other way around: the user tabel must contain a level_one_id.
And you should add it in the User migration, something like:
$table->int('level_one_id');
$table->foreign('level_one_id')->references('id')->on('level_one');
Now you have (in the database) a connection between User and LevelOne.
Now, if you query a user in your code, you should be able to get the LevelOne stuff as well. Make sure to really read the official Laravel documentation on relationships! It will really help you with examples.

Resources