Laravel 6.5.2 error when registering on overwritten users table - laravel

I have overwritten the default user table with an existing table.
When trying to register a new user i get the following error:
Argument 1 passed to Illuminate\Auth\SessionGuard::login() must be an instance of Illuminate\Contracts\Auth\Authenticatable, instance of App\customUser given, called in {path}\vendor\laravel\framework\src\Illuminate\Foundation\Auth\RegistersUsers.php on line 35
To overwrite the default users table with my own I have made the following changes:
///Auth.php///
//Auth defaults:
'defaults' => [
'guard' => 'web',
'passwords' => 'customusers',
],
//Auth guards:
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'customusers',
],
//User providers:
'providers' => [
'customusers' => [
'driver' => 'eloquent',
'model' => App\customUser::class,
],
I don't know if these changes could cause the error I'm facing.
The error is supposedly fired in this part of 'RegisterUsers.php'
$this->guard()->login($user);
This is part of the function 'register', which looks like this:
public function register(Request $request)
{
$this->validator($request->all())->validate();
event(new Registered($user = $this->create($request->all())));
$this->guard()->login($user);
return $this->registered($request, $user)
?: redirect($this->redirectPath());
}
Any help regarding this error would be kindly appreciated, I'm fairly new to Laravel so I would like to recieve a clear explanation to my problem so I can understand why it is calling this error.
Kind regards,
geertjanknapen

Your model needs to extend Illuminate\Foundation\Auth\User, otherwise you cannot use it with the authentication methods like login / logout etc.
In your customUser model add the following:
use Illuminate\Foundation\Auth\User as Authenticatable;
class customUser extends Authenticatable
I would also recommend to rename your class customUser to CustomUser in order to follow PSR-1:
Class names MUST be declared in StudlyCaps.
The term ‘StudlyCaps’ in PSR-1 MUST be interpreted as PascalCase where
the first letter of each word is capitalized including the very first
letter.

On RegisterUsers.php you need to include
use Illuminate\Foundation\Auth\AuthenticatesUsers;
and below class RegisterUsers extends Controller
you need to add
use AuthenticatesUsers;

Related

Mapping different column and table names for Laravel Authentication without re-writing all of the auth classes

We store our authentication information in a different table and column names than Laravel uses by default. It's still stored in MySQL. When doing research, in the documentation it says that we have to write completely different authentication handlers.
Is there really not any way to just remap the table and column names in a central place?
If not is there a better way to handle this? Should we just create a new table using the authentication information?
You can change your table/model name for authentication purposes inside the config\auth.php file.
'providers' => [
'users' => [
'driver' => 'eloquent',
'model' => App\User::class,
],
// 'users' => [
// 'driver' => 'database',
// 'table' => 'users',
// ],
],
Now, when it comes to changing column name by default Laravel using email field which you can change by putting a function username() which will return the field to be used for authentication inside LoginController.php.
public function username()
{
return 'username';
}
Hopefully this helps.
The Model associated with the login process can be modified in:
config/auth.php
under the 'providers' section:
'providers' => [
'users' => [
'driver' => 'eloquent',
'model' => \App\Models\MyOwnUsersTable::class,
],
],
However, the login process is a bit more tricky. the LoginController uses the AuthenticatesUsers trait, where you may override the required methods. For example the login method
class LoginController extends Controller
{
use AuthenticatesUsers;
public function login(Request $request)
{
//Do whatever you have to do
return $this->sendLoginResponse($request);
}
}
So, basically, I encourage you to study the
Illuminate\Foundation\Auth\AuthenticatesUsers
and reuse as much as possible from that class, and only override the methods you need to.

Can I change Model User that used in auth system in laravel?

I tried to change User Model that used by default when use command php artisan ui:auth
to another model
but all of way to do that is not working
What should to do that ?
I am using laravel version 7.x
You can have different (or as many different) models as you want for various reasons. You just need to change the relevant section in config/auth.php. I always use a Models directory, so one of the first things I do with a new app is to relocate the User model and then tell Auth where to look for it:
'providers' => [
'users' => [
'driver' => 'eloquent',
'model' => App\Models\User::class,
],
// 'users' => [
// 'driver' => 'database',
// 'table' => 'users',
// ],
],
You also have to update the model's use statements in your controllers if you have custom logic, but for a vanilla Laravel Auth set-up, you should be good just by changing the config.
Edit: If you do have a structure like mine (a models directory) the default App\User namespace declaration has to change on the model itself:
Change:
namespace App;
To:
namespace App\Models;
Or whatever it is that matches your structure.

Auth::user(); doesn't returns users, using passport

I have situation about returning users from DB. In my controller I am trying it like below:
UPDATED:
NOTE: for clear misunderstanding. Actually I am logged in as a user. No problem with that part. But it looks like auth:: doesn't understand that and when I try to retrieve users. it's redirecting me to login's endpoint...
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use Auth;
class UsersController extends Controller
{
public function getUser(){
$users = Auth::user();
dd($users);
}
}
And about the api route:
Route::group(['middleware' => 'auth:api'], function() {
Route::post("logout", "Api\AuthController#logout");
/* User */
Route::get('/user', 'Api\UsersController#getUser');
});
Route::group(["prefix" => "v1"], function(){
/* Auth */
Route::post("login", "Api\AuthController#login")->name("login");
Route::post("register", "Api\AuthController#register");
});
Here is the thing. If I use my UserController route outside the middleware:api then endpoint is returns null. And if use it inside the middleware it redirects me to my login's endpoint. Because of the "->name('login')"
In the end I can't return the users. Additionally this is what config/auth looks like.
'defaults' => [
'guard' => 'web',
'passwords' => 'users',
],
By the way before asked. I tried to change guard's web to api but nothing is changed.
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
'api' => [
'driver' => 'passport',
'provider' => 'users',
],
],
Is there anyone have better understanding on this situation. How can I return users with using passport? Do I missing something here?
Apparently, the problem is with the request header. Only a logged in user can call /api/user endpoint with an access_token in the request header.
Request header will have this pair
Authorization: Bearer eyJ0eXAiOiJKV1..........
Nothing to do in laravel part, as it's working as expected.
If you are using Laravel Passport. Let's read and make your step same in document: https://laravel.com/docs/5.8/passport
From your API request, need to pass the access_token to backend.
Hoping you can resolve that issue!

Laravel: How to use Gates with multiple Guards

I have a traditional web application that has a number of different user types, and each user type has its own Authentication guard.
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
'admin' => [
'driver' => 'session',
'provider' => 'admin',
],
'timekeeper' => [
'driver' => 'session',
'provider' => 'timekeeper',
],
'api' => [
'driver' => 'token',
'provider' => 'users',
],
],
Most my users authenticate using the 'web' guard, however administrators and timekeepers each use their own guard, which is attached to an appropriate user provider.
This is fine until I try to use authentication gates. If I authenticate a user against the system's default guard (e.g. 'web'), then the gates work as expected. If I authenticate against any other guard however, then all Gate::allows(...) calls are DENIED.
Even the following ability is denied:
Gate::define('read', function ($user) {
return true;
});
Presumably this is due to line 284-286 in Illuminate\Auth\Access\Gate:
if (! $user = $this->resolveUser()) {
return false;
}
As far as I can see, my options are to:
Go back to using a single 'web' guard, with a user provider that can locate any type of user (but I'm not sure how that would work if I start using an API in parallel)
Somehow set the default guard at run time, depending on the type of the current user. (It is currently set in the config file)
Somehow inject a different user resolver in to the Gate facade (again, depending on the type of the current user)
None of these seems intuitive however. Am I missing something?
It's not the most elegant solution because it requires a lot of extra boilerplate code, but you can use Gate::forUser($user)->allows() instead of just Gate::allows() where $user comes from Auth::guard().
I had the same problem and I didn't really like this solution. After quite a lot of research I came up with this way to make your own user resolver in the Gate:
public function register()
{
$this->app->singleton(GateContract::class, function ($app) {
return new \Illuminate\Auth\Access\Gate($app, function () use($app) {
$user = call_user_func($app['auth']->userResolver());
if (is_null($user)) {
// Implement your own logic for resolving the user
}
return $user;
});
});
}
I put this in my AuthServiceProvider.

Add custom values in drop down in laravel backpack

I am using laravel back and and I have two tables called bundles and study. I added a drop down fields in the form from bundleCrudController. But I just want to add only those values in the drop down list which studies are created by the logged in user not all the data from studies table.
Here is my code to add data in drop down list -
$this->crud->addField([
'name' => 'studies',
'label' => 'Studies',
'type' => 'select2_from_array',
'options' => $this->Study->getUnallocatedStudies($entryId),
'allows_null' => false,
'hint' => 'Search for the studies you would like to add to this bundle',
'tab' => 'Info',
'allows_multiple' => true
]);
$this->crud->addColumn([
'label' => 'Studies',
'type' => "select_multiple",
'name' => 'bundle_id',
'entity' => 'studies',
'attribute' => 'name',
'model' => "App\Models\Study",
]);
So pls help me to resolve the problem to add only those records in the dropdownlist created by the logged in user not all records.. Thanx
I think the best way would be to create an additional model, UserStudy, that:
extends Study;
has a global scope for filtering for what the current user can see;
It should look something like this:
<?php
namespace App\Models;
use App\Models\Study;
use Auth;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Builder;
class UserStudy extends Study
{
/**
* The "booting" method of the model.
*
* #return void
*/
protected static function boot()
{
parent::boot();
// filter out the studies that don't belong to this user
if (Auth::check()) {
$user = Auth::user();
static::addGlobalScope('user_id', function (Builder $builder) use ($user) {
$builder->where('user_id', $user->id);
});
}
}
}
You'll then be able to use this UserStudy model in your field definition, instead of Study. Just replace App\Models\Study with App\Models\UserStudy.
Hope it helps. Cheers!

Resources