Laravel Auth::hasUser always false in Global Scope - php

I have the following code in my model:
protected static function boot()
{
parent::boot();
static::addGlobalScope(new CompanyScope);
}
Here is my CompanyScope:
class CompanyScope implements Scope
{
public function apply(Builder $builder, Model $model)
{
\Log::info('apply');
if (Auth::hasUser()) {
\Log::info('auth');
$builder->where($model->getTable() . '.company_id', company()->id);
}
}
}
In my log, I only see apply, I do not see auth, nor is the scope being applied.
Why?

I just tested what you have here except I've used \Illuminate\Support\Facades\Log rather than \Log and it seems it works fine as long as you are actually testing it with the authenticated user:
app/User.php
<?php
namespace App;
use App\Scopes\CompanyScope;
use Illuminate\Foundation\Auth\User as Authenticatable;
class User extends Authenticatable
{
protected static function boot()
{
parent::boot();
static::addGlobalScope(new CompanyScope);
}
}
app/Scopes/CompanyScope.php
<?php
namespace App\Scopes;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Log;
use Illuminate\Database\Eloquent\Scope;
class CompanyScope implements Scope
{
public function apply(Builder $builder, Model $model)
{
Log::info('apply');
if (Auth::hasUser()) {
Log::info('auth');
$builder->where($model->getTable() . '.company_id', company()->id);
}
}
}
In my controller I just fetch the user with id 1:
/**
* Get landing view.
*
* #return \Illuminate\Http\JsonResponse
*/
public function index(): JsonResponse
{
$user = User::find(1);
return new JsonResponse([
'user' => $user,
]);
}
and the corresponding test:
/**
* #test
*/
public function global_scope()
{
$this->actingAs($user = factory(User::class)->create(['id' => 1]));
$this->assertTrue($user->exists);
$this->assertAuthenticatedAs($user);
$response = $this->get(route('home'));
$response->assertExactJson([
'user' => $user->toArray()
]);
}
After running the test, my log file contains:
[2020-02-16 14:18:59] testing.INFO: apply
[2020-02-16 14:18:59] testing.INFO: auth
If you try the same without logging the user in, then only apply will be logged.

Related

Auth::check() works only in middleware laravel [duplicate]

I'm using Laravel 5.3 and I'm trying to get the authenticated user's id in the constructor method so I can filter the user by assigned company as follows:
namespace App\Http\Controllers;
use Illuminate\Foundation\Bus\DispatchesJobs;
use Illuminate\Routing\Controller as BaseController;
use Illuminate\Foundation\Validation\ValidatesRequests;
use Illuminate\Foundation\Auth\Access\AuthorizesRequests;
use Illuminate\Support\Facades\View;
use App\Models\User;
use App\Models\Company;
use Illuminate\Support\Facades\Auth;
class Controller extends BaseController
{
use AuthorizesRequests, DispatchesJobs, ValidatesRequests ;
public $user;
public $company;
public function __construct()
{
$companies = Company::pluck('name', 'id');
$companies->prepend('Please select');
view()->share('companies', $companies);
$this->user = User::with('profile')->where('id', \Auth::id())->first();
if(isset($this->user->company_id)){
$this->company = Company::find($this->user->company_id);
if (!isset($this->company)) {
$this->company = new Company();
}
view()->share('company', $this->company);
view()->share('user', $this->user);
}
}
However this doesn't return the user id. I've even tried Auth::check() and it doesn't work.
If I move the Auth::check() out of the __construct() method then this works as follows:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
class HomeController extends Controller
{
/**
* Create a new controller instance.
*
* #return void
*/
public function __construct()
{
parent::__construct();
$this->middleware('auth');
}
/**
* Show the application dashboard.
*
* #return \Illuminate\Http\Response
*/
public function index()
{
dd(\Auth::check());
return view('home');
}
}
However this fails if I put this in the construct method in the HomeController too!
Any ideas why this is failing?
docs
you can't access the session or authenticated user in your
controller's constructor because the middleware has not run yet.
As an alternative, you may define a Closure based middleware directly
in your controller's constructor. Before using this feature, make sure
that your application is running Laravel 5.3.4 or above:
class ProjectController extends Controller
{
/**
* All of the current user's projects.
*/
protected $projects;
/**
* Create a new controller instance.
*
* #return void
*/
public function __construct()
{
$this->middleware(function ($request, $next) {
$this->projects = Auth::user()->projects;
return $next($request);
});
}
}
Since 5.3 Auth::check will not work in a controller's construtor, it's one of undocumented changes. So, you need to move it to middleware or do check in controller methods instead or move project to 5.2.x.
It fails because you call $this->middleware('auth'); after parent::__construct();. It means that you auth middleware is not loaded properly.

Unauthorized laravel 5

I try to use Laravel's access policies, however, I receive over and over and over and over again the same error and I do not see what I need to import and / or use in functions or models.
First I show you my AuthServiceProvider
use Illuminate\Support\Facades\Gate;
use App\User;
use App\Policies\UserPolicy;
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as
ServiceProvider;
class AuthServiceProvider extends ServiceProvider
{
protected $policies = [
User::class => UserPolicy::class,
];
public function boot()
{
$this->registerPolicies();
//
}
}
Now my UserPolicy
namespace App\Policies;
use App\User;
use Illuminate\Auth\Access\HandlesAuthorization;
class UserPolicy
{
use HandlesAuthorization;
public function __construct()
{
//
}
public function edit(User $authUser, User $user)
{
return $authUser === $user;
}
}
And finally the edit function of my UsersControllers
use App\User;
use Illuminate\Http\Request;
use App\Http\Requests\UpdateUserRequest;
public function edit($id)
{
$user = User::findOrFail($id);
$this->authorize($user);
return view('users.edit', compact('user'));
}
With my UpdateUserRequest with authorize
namespace App\Http\Requests;
use Illuminate\Foundation\Http\FormRequest;
class UpdateUserRequest extends FormRequest
{
/**
* Determine if the user is authorized to make this request.
*
* #return bool
*/
public function authorize()
{
return true;
}
/**
* Get the validation rules that apply to the request.
*
* #return array
*/
public function rules()
{
return [
'name' => 'required',
'email' => 'required|unique:users,email,'.$this->route('usuario')
];
}
}
When I try to access it always tells me that I do not have authorization, even if I modify the edit function of UserPolicy.
Your authorization call is wrong. The first argument of the authorization method needs to be the action you are trying to authorize. So the correct code for authorization check would be:
$this->authorize('edit', $user);
You are using identity operator === for comparing the user models. Like return $authUser === $user;.
According to the php manual:
When using the identity operator (===), object variables are identical if and only if they refer to the same instance of the same class.
However, the $authUser instance and $user instance are different instances of same model. Use the comparison operator ==.
When using the comparison operator (==), object variables are compared in a simple manner, namely: Two object instances are equal if they have the same attributes and values (values are compared with ==), and are instances of the same class.
Now your user policy method will be:
public function edit(User $authUser, User $user) {
return $authUser == $user;
}

laravel 5.4 - return post exact model in eloquent model

I have a Post model and two TextPost and PhotoPost models extending from it.
I want to do something like Post::find(1); and if the record with id=1 have type=photo attribute, it should return me an instance of PhotoPost model otherwise should be an instance of TextPost model. how can do this in laravel 5.4? my classes are as below:
Post.php
namespace App;
use Illuminate\Database\Eloquent\Model;
class Post extends Model
{
protected $fillable = ['file_id', 'file', 'bot_id', 'text'];
public function bot()
{
return $this->belongsTo(Bot::class);
}
}
TextPost.php
namespace App;
use App\Traits\TextPostTrait;
class TextPost extends Post
{
use TextPostTrait;
protected $table = 'posts';
protected $fillable = ['bot_id', 'text'];
protected $attributes = ['type' => 'text'];
}
PhotoPost.php
namespace App;
use App\Traits\PhotoPostTrait;
class PhotoPost extends Post
{
use PhotoPostTrait;
protected $table = 'posts';
protected $attributes = ['type' => 'photo', 'image_watermark'];
}
PhotoPostTrait.php
namespace App\Traits;
use App\Scopes\PhotoPostScope;
trait PhotoPostTrait
{
public static function bootPhotoPostTrait()
{
static::addGlobalScope(new PhotoPostScope());
}
}
TextPostTrait.php
namespace App\Traits;
use App\Scopes\TextPostScope;
trait TextPostTrait
{
public static function bootSettingsTrait()
{
static::addGlobalScope(new TextPostScope());
}
}
TextPostScope.php
namespace App\Scopes;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\ScopeInterface;
class TextPostScope implements ScopeInterface
{
public function apply(Builder $builder, Model $model)
{
$builder->where('type', 'text');
}
public function remove(Builder $builder, Model $model)
{
}
}
PhotoPostTrait.php
namespace App\Scopes;
use \Illuminate\Database\Eloquent\Model;
use \Illuminate\Database\Eloquent\Builder;
use \Illuminate\Database\Eloquent\Scope;
class PhotoPostScope implements Scope
{
public function apply(Builder $builder, Model $model)
{
$builder->where('type', '=', 'photo');
}
public function remove(Builder $builder, Model $model)
{
}
}
so I use globalScopes to categorize my post types. so basically I store them in a single table. so I should add the $table='posts'; so that laravel does not take it as a seperate model. and using traits to boot the scope. and inside the scopes I will make sure the record is a Photo or a Text.
EDIT
I found a solution by JarekTkaczyk at https://laracasts.com/discuss/channels/eloquent/multiple-models-to-same-table
But I want to know does laravel a native solution for this problem?

ErrorException in EloquentUserProvider.php line 114: Argument 1 passed to Illuminate\Auth\EloquentUserProvider::validateCredentials

I am trying to authenticate my user with the help of Helpers
For this purpose i have make Helper folder in app directory. Add the following lines of code to the composer.json
"files": [
"app/Helpers/UserHelper.php"
],
Make HelperServiceProvider.php in App\Provider directory, and use the following code in it.
<?php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
class HelperServiceProvider extends ServiceProvider
{
/**
* Bootstrap any application services.
*
* #return void
*/
public function boot()
{
//
}
/**
* Register any application services.
*
* #return void
*/
public function register()
{
foreach (glob(app_path().'/Helpers/*.php') as $filename){
require_once($filename);
}
}
}
after this i have add alias in app.php as well as add provide like this
//this is an alias
'UserHelper' => App\Helpers\UserHelper::class,
//this is an provider
App\Providers\HelperServiceProvider::class,
My User model is
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class User extends Model {
protected $table='users';
protected $fillable =['username', 'password', 'firstname', 'lastname', 'email', 'phone', 'groupname', 'about', 'image'];
public static $login = [
'username' => 'required|',
'email' => 'required|',
'password' => 'required'
];
}
This my UserHelper
<?php namespace App\Helpers;
use Illuminate\Support\Facades\Auth;
class UserHelper {
public static function processLogin($inputs){
if(Auth::attempt($inputs)){
return TRUE;
} else {
return FALSE;
}
}
}
Here is my Login Function
<?php
namespace App\Http\Controllers;
use App\User;
use Input;
use Illuminate\Support\Facades\Validator as Validator;
use App\Helpers\UserHelper;
class LoginController extends Controller
{
public function login() {
$inputs = Input::except('_token');
$validator = Validator::make($inputs, User::$login);
if($validator->fails()){
print_r($validator->errors()->first());
} else {
$respones = \UserHelper::processLogin($inputs);
if($respones){
return 'loginView';
} else {
return 'not a user of our DB';
}
}
}
}
I have also updated my composer and after i login to application following error comes up , i am searching this for last 5 hour any help ?
Reards
In your code you are extending the class User extends Model but when you are using auth functionality in laravel you need to extend the auth rather than model..
Keep Illuminate\Foundation\Auth\User and extends the model like this...
class User extends Authenticatable{
//code here
}

Laravel view share doesnt work in modularing system

simply i can use modular system in laravel, but i cant use view share in this solution,
app/Http/Controllers/Controller.php
abstract class Controller extends BaseController
{
use AuthorizesRequests, DispatchesJobs, ValidatesRequests;
public function __construct()
{
view()->share('name', 'MY NAME');
}
}
app/Modules/NewCurrency/Controllers/IndexController.php
class IndexController extends Controller
{
public function __construct()
{
parent::__construct();
}
/**
* Display a listing of the resource.
*
* #return \Illuminate\Http\Response
*/
public function index()
{
return view('layouts.admin.new_user.index');
}
}
resources/views/layouts/admin.new_user.index.blade.php
{{ $name }}
I get this Error:
Undefined variable: name
Did you check this
View::share()
Because the method that you wrote is used by other way. You should place calls to share within a service provider's boot method.
<?php
namespace App\Providers;
class AppServiceProvider extends ServiceProvider
{
public function boot()
{
view()->share('key', 'value');
}
public function register()
{
//
}
}

Categories