Access restriction for users that are not admin and landlord - php

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.

Related

Middleware for 2 step authorization

I am beginner in Laravel. I make my application in Laravel 8 and spatie/laravel-permission.
Actually i have persimmons: individual|company
Route::group(['prefix' => '', 'middleware' => ['role:individual|company']], function () {
Route::get('/cms-historia-przesylek-nadanych', 'Account\SendPackageController#index')->name('cms-history-send-packages')->middleware('company');
Route::get('/cms-przesyleka-nadana/{id}', 'Account\SendPackageController#show')->name('cms-view-send-package')->middleware('company');
Route::get('/cms-przesyleka-nadana-zwrot/{id}', 'Account\SendPackageController#returnBackPackage')->name('cms-view-send-package-return')->middleware('company');
Route::post('/cms-przesyleka-nadana-zwrot/zamow-paczke/{id}', 'Account\SendPackageController#orderPackage')->name('cms-view-send-package-return-order')->middleware('company');
Route::get('/cms-pobierz-przesyleke-nadana/{id}', 'Account\SendPackageController#getPdf')->name('cms-get-send-package')->middleware('company');
Route::get('/cms-historia-przesylek-odebranych', 'Account\ReceivedPackageController#index')->name('cms-history-received-packages')->middleware('company');
Route::get('/cms-przesyleka-odebrana/{id}', 'Account\ReceivedPackageController#show')->name('cms-view-received-package')->middleware('company');
Route::get('/cms-pobierz-przesyleke-odebrana/{id}', 'Account\ReceivedPackageController#getPdf')->name('cms-get-received-package')->middleware('company');
Route::get('/cms-dwu-stopniowa-weryfikacja', 'Account\TwoStepVerificationController#index')->name('cms-two-step-verification');
});
And this is my USER.php:
<?php
namespace App\Models;
use App\Traits\ScopeActiveTrait;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\SoftDeletes;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Spatie\Permission\Traits\HasRoles;
use Spatie\Sluggable\HasSlug;
use Spatie\Sluggable\SlugOptions;
class User extends Authenticatable
{
use Notifiable,
ScopeActiveTrait,
HasRoles,
SoftDeletes,
HasSlug;
/**
* Get the options for generating the slug.
*/
public function getSlugOptions() : SlugOptions
{
return SlugOptions::create()
->generateSlugsFrom(['company_name', 'id'])
->slugsShouldBeNoLongerThan(250)
->saveSlugsTo('slug');
}
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $fillable = [
'name',
'email',
'password',
'enable',
'company_id',
'surname',
'email_verified_at',
'description',
'is_company',
'package1',
'package2',
'package3',
'sms',
'phone',
'street',
'building_number',
'city',
'postal_code',
'revicer_default_inpost_parcel',
'shipping_default_inpost_parcel',
'file_name',
'nip',
'company_name',
'remember_token',
'subdomain',
'lng',
'lat',
'show_map',
'ofert_type',
'discount_value1',
'discount_value2',
'discount_value3',
'discount_value4',
'discount_value5',
'is_two_step_authorization',
'two_step_authorization_token',
];
protected $dates = [
'created_at',
'updated_at',
'deleted_at'
];
/**
* 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',
'company_id' => 'integer',
'enable'=>'boolean',
'isCompany'=>'boolean',
'show_map'=>'boolean',
];
/* User Login history */
public function loginHistory()
{
return $this->hasMany('App\Models\UserLoginHistory');
}
/* User images */
public function images()
{
return $this->hasManyThrough('App\Models\UploadFile', 'App\Models\User', 'id', 'file_id');
}
public function mainImage()
{
return $this->images()->where('file_type', 'DZ_ADMIN');
}
/* Admin Avatar */
public function getAvatar()
{
return $this->images()->where('file_type', 'DZ_ADMIN')->orderBy('order', 'ASC')->first();
}
public function isCompany(): bool
{
return $this->is_company == 1;
}
}
When I have is_two_step_authorization = 1.- then I need run new middleware for 2 step authorization,.
How can I make it?
is_two_step_authorization = 0 - 2 factorial authorization is disabled. is_two_step_authorization = 1 - Two-factor authentication is enabled.
I think use this tutorial: https://www.itsolutionstuff.com/post/laravel-8-two-factor-authentication-with-smsexample.html but this middleware work always for route with middleware 2fa.
In my case, selected routs may require 2-step security (if the user has chosen so in the settings) or not (the user has disabled security).
How can I change the code from the tutorial to get it?
You need to update the middleware from the tutorial in order to only redirect to 2fa index if the logged user has is_two_step_authorization on. Of course you may need other checks, or to ensure that the user is logged in and so on, but just for this specific usecase, this line of code should do the trick.
app/Http/Middleware/Check2FA.php
public function handle(Request $request, Closure $next)
{
if ($request->user()->is_two_step_authorization && !Session::has('user_2fa')) {
return redirect()->route('2fa.index');
}
return $next($request);
}
Tweak the code from that example...
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Http\Request;
use Session;
class Check2FA
{
/**
* Handle an incoming request.
*
* #param \Illuminate\Http\Request $request
* #param \Closure $next
* #return mixed
*/
public function handle(Request $request, Closure $next)
{
if ($request->user()->is_two_step_authorization == 1) {
return redirect()->route('2fa.index');
}
return $next($request);
}
If the requested user has the property of is_two_step_authorization with value one only then it will redirect to the 2fa page, otherwise not

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() )

Laravel Auth Session Missing After Redirect(with web middleware)

im using laravel 7.14
I'm using laravel's Auth to do a login process and keep my application authenticated using username and password in my database. Here is my route:
Route::group(['middleware' => 'web'], function () {
Route::post('/user/login', 'UserController#loginUser');
});
and my login function
public function loginUser(Request $request)
{
$field = 'email';
if (is_numeric(Request()->username)) {
$field = 'mobile';
} elseif (filter_var(Request()->username, FILTER_VALIDATE_EMAIL)) {
$field = 'email';
}
if ($field == "mobile") {
$user = User::where("mobile",'=',Request()->username)->first();
}
else{
$user = User::where("email",'=',Request()->username)->first();
}
if($user){
Auth::login($user, Request()->filled('remember'));
$data = ["status" => true,"mobile_verified" => Auth::user()->mobile_verified];
return response($data)
->header("Access-Control-Allow-Origin", config('cors.allowed_origins'))
->header("Access-Control-Allow-Methods", config('cors.allowed_methods'));
}
else
{
$data = ["status" => false];
return response($data)
->header("Access-Control-Allow-Origin", config('cors.allowed_origins'))
->header("Access-Control-Allow-Methods", config('cors.allowed_methods'));
}
}
but after redirect i check Auth::guest() and it is true.
i searched a lot and solutions is use of web middleware but its not work for me
UPDATE:
My User Model Is:
<?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.
*
* #var array
*/
protected $fillable = [
'name','family', 'email','mobile','tel','state','city','verification_code','district','address','role', 'password',
];
/**
* 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',
];
}

Laravel multi table authentication is not logging in

In my laravel project , am implementing another login for agencies, which i want to take from agencies table.Agencies table have email and password fields. But when i try to login it not get logged in and redirecting to same page and prducing validation error.But i provided exact email and password from agencie table
Following is my code in model
<?php
namespace App;
use Illuminate\Notifications\Notifiable;
use Kyslik\ColumnSortable\Sortable;
use Illuminate\Foundation\Auth\User as Authenticatable;
class Agencie extends Authenticatable
{
use Notifiable;
use Sortable;
protected $guard = 'agencie';
protected $table = 'agencies';
protected $primaryKey = 'agency_id';
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $fillable = [
'agency_id', 'agency_name','agency_user_name' ,'agency_password', 'agency_city', 'agency_state', 'agency_zip', 'agency_email','status','created_at','updated_at'
];
}
Following i have addeed to config/auth.php
'guards' => [
'agencie' => [
'driver' => 'session',
'provider' => 'agencies',
],
],
'providers' => [
'agencies' => [
'driver' => 'eloquent',
'model' => App\Agencie::class,
],
],
Following is my code in LoginController
<?php
namespace App\Http\Controllers\Agency\AgencyAuth;
use App\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\AuthenticatesUsers;
use Illuminate\Support\Facades\Auth;
use Hesto\MultiAuth\Traits\LogsoutGuard;
use JsValidator;
class LoginController extends Controller
{
/*
|--------------------------------------------------------------------------
| Login Controller
|--------------------------------------------------------------------------
|
| This controller handles authenticating users for the application and
| redirecting them to your home screen. The controller uses a trait
| to conveniently provide its functionality to your applications.
|
*/
use AuthenticatesUsers, LogsoutGuard {
LogsoutGuard::logout insteadof AuthenticatesUsers;
}
protected $validationRules = [
'email' => 'required|email',
'password' => 'required'
];
/**
* Where to redirect users after login / registration.
*
* #var string
*/
// public $redirectTo = '/user/home';
public $redirectTo = '/user/dashboard-graph';
/**
* Create a new controller instance.
*
* #return void
*/
public function __construct()
{
$this->middleware('guest:agencie', ['except' => 'logout']);
// $this->middleware('guest:agency')->except('logout');
}
public function username()
{
return 'agency_email';
}
/**
* Show the application's login form.
*
* #return \Illuminate\Http\Response
*/
public function showLoginForm()
{
$validator = JsValidator::make($this->validationRules,[],[],'#loginform');
return view('agency.auth.login')->with('validator', $validator);
}
/**
* Get the guard to be used during authentication.
*
* #return \Illuminate\Contracts\Auth\StatefulGuard
*/
protected function guard()
{
return Auth::guard('agencie');
}
/**
* Get the needed authorization credentials from the request.
*
* #param \Illuminate\Http\Request $request
* #return array
*/
}
I have added following codes to app/Expecations/Handler.php
protected function unauthenticated($request, AuthenticationException $exception)
{
if ($request->expectsJson()) {
return response()->json(['error' => 'Unauthenticated.'], 401);
}
$middleware = request()->route()->gatherMiddleware();
$guard = config('auth.defaults.guard');
foreach($middleware as $m) {
if(preg_match("/auth:/",$m)) {
list($mid, $guard) = explode(":",$m);
}
}
switch($guard) {
case 'agencie':
$login = 'agency/login';
break;
default:
$login = 'user/login';
break;
}
return redirect()->guest($login);
}
I have also added additonal 2 files in middleware named RedirectifAgency.php & Redirectifnotagency.php
Following is the code
<?php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Support\Facades\Auth;
class RedirectIfAgency
{
/**
* 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 = 'agencie')
{
if (Auth::guard($guard)->check()) {
return redirect('agency/home');
}
return $next($request);
}
}
What is the problem here.Please help

Laravel policy return unauthorized

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

Categories