Method Illuminate\\Auth\\RequestGuard::attempt does not exist - php

I just install Laravel passport as follow:
Admin Model:
use Laravel\Passport\HasApiTokens;
use Illuminate\Notifications\Notifiable;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
class Admin extends Authenticatable
{
use HasApiTokens, HasFactory, Notifiable;
protected $table = 'admins';
}
I just have one guard in auth.php which is API and it's by default.
'defaults' => [
'guard' => 'api',
'passwords' => 'admins',
],
'guards' => [
'api' => [
'driver' => 'passport',
'provider' => 'admins',
'hash' => false,
],
],
LoginController:
use Illuminate\Support\Facades\Auth;
use App\Http\Resources\LoginRequest;
use App\Http\Controllers\Controller;
class LoginController extends Controller
{
public function __invoke(LoginRequest $request)
{
$credentials = $request->only(['email', 'password']);
if (!Auth::attempt($credentials)) {
return $this->jsonResponse(null, trans('auth.failed'), 401);
}
$admin = Auth::user();
$token = $admin->createToken('MyApp')->accessToken;
return (new AdminResourse($admin))->additional([
'meta' => ['token' => $token]
]);
}
}
I got this error in postman:
Method Illuminate\\Auth\\RequestGuard::attempt does not exist.
I clear the cache too, and still same error

I believe the attempt is only available for routes with web middleware.
However you can do:
if (!Hash::check($request->password, $user->password) {
return $this->jsonResponse(null, trans('auth.failed'), 401);
}

The issue with default guard. So it should be web
'defaults' => [
'guard' => 'web',
'passwords' => 'users',
],
If you keep defaults guard to api then we should manually pass guard
if (!Auth::guard('web')->attempt($credentials)) {
}

Related

Laravel: Auth guard [sanctum] is not defined

I'm trying to implement auth in Laravel via Sanctum. I did all steps from documentation. Generation of Token works fine but when I try to use auth:sanctum middleware it returns the error Auth guard [sanctum] is not defined.
Here are my files:
/routes/api.php
<?php
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\Dashboard;
Route::middleware('auth:sanctum')->get('/dashboard/get_current_client/', [Dashboard::class, 'get_current_client']);
Route::get('/dashboard/client_data/', [Dashboard::class, 'client_data']);
/config/auth.php
<?php
return [
'defaults' => [
'guard' => 'web',
'passwords' => 'users',
],
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
'api' => [
'driver' => 'token',
'provider' => 'users',
'hash' => false,
],
],
'providers' => [
'users' => [
'driver' => 'eloquent',
'model' => App\Models\Client::class,
],
// 'users' => [
// 'driver' => 'database',
// 'table' => 'users',
// ],
],
'passwords' => [
'users' => [
'provider' => 'users',
'table' => 'password_resets',
'expire' => 60,
'throttle' => 60,
],
],
'password_timeout' => 10800,
];
/app/Models/Client.php
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
use Laravel\Sanctum\HasApiTokens;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
class Client extends Authenticatable
{
use HasFactory, HasApiTokens, Notifiable;
protected $table = 'client';
protected $primaryKey = 'client_id';
public $timestamps = false;
}
/app/Http/Controllers/Dashboard.php
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Models\Client;
class Dashboard extends Controller
{
public function client_data () {
$user = Client::where('client_id', 1)->first();
return $user->client_id;
}
public function get_current_client(Request $request) {
var_dump($request->user());
}
}
I found the problem. For some reason cache in /bootstrap/cache has not updated. After manual removing it, everything started working.
to fix it add the below code to file "/bootstrap/cache/packages.php"
'laravel/sanctum' => array (
'providers' =>
array (
0 => 'Laravel\\Sanctum\\SanctumServiceProvider',
), ),

Call to undefined method Illuminate\Auth\TokenGuard::attempt() in laravel

I'm using Laravel 6.x and passport package.
I used api_token in App\User before installing this package.
Now I want to authenticate Users with passport package but I am experiencing this error,
Call to undefined method Illuminate\Auth\TokenGuard::attempt()
This is my gaurd:
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
'api' => [
'driver' => 'passport',
'provider' => 'users',
],
],
This is my authController:
<?php
namespace App\Http\Controllers\Api;
use App\Http\Controllers\Controller;
use App\User;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Str;
class AuthController extends Controller
{
private $successStatus=200;
public function login(){
if(Auth::attempt(['email' => request('email'), 'password' => request('password')])){
$user = Auth::user();
$success['token'] = $user->createToken('MyApp')-> accessToken;
return response()->json(['success' => $success], $this-> successStatus);
}
else{
return response()->json(['error'=>'Unauthorised'], 401);
}
}
}
You may be having the following configuration:
change your auth.php
passport to token
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
'api' => [
'driver' => 'token',
'provider' => 'users',
],
I changed my controller to this and the problem was resolved
<?php
namespace App\Http\Controllers\Api;
use App\Http\Controllers\Controller;
use App\User;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Str;
class AuthController extends Controller
{
public function login(Request $request){
$user = User::whereEmail($request->email)->first();
if($user && Hash::check($request->password, $user->password)){
$success['token'] = $user->createToken('tp_#1')-> accessToken;
return response()->json(['success' => $success],200);
}
else{
return response()->json(['status'=>'invalid username or pass !'], 401);
}
}
}

Laravel multi auth and authorize resource

I've got an issue with the following scenario an I hope to find advice here:
I've got Laravel 5.7 installed and ran make:auth for the authentication scaffolding. The native User model has been removed and instead I'm using two custom models "Customer" and "Admin" (migrations have been changed accordingly).
Admin model:
namespace App;
use Illuminate\Notifications\Notifiable;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Foundation\Auth\User as Authenticatable;
use App\Traits\FormatUserdata;
class Admin extends Authenticatable
{
use Notifiable, FormatUserdata;
protected $guard = 'admin';
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $fillable = [
'firstname', 'lastname', 'email', 'password',
];
/**
* The attributes that should be hidden for arrays.
*
* #var array
*/
protected $hidden = [
'password', 'remember_token',
];
}
Customer model:
namespace App;
use Laravel\Passport\HasApiTokens;
use Illuminate\Notifications\Notifiable;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Foundation\Auth\User as Authenticatable;
use App\Traits\FormatUserdata;
class Customer extends Authenticatable
{
use HasApiTokens, Notifiable, FormatUserdata;
protected $guard = 'customer';
protected $fillable = [
'firstname', 'lastname', 'email', 'company', 'address', 'zip', 'city', 'country', 'vatid', 'customer_no', 'password',
];
protected $hidden = [
'password', 'remember_token',
];
public function licenses()
{
return $this->hasMany('App\License');
}
}
So I have to authenticate users from two different models and tables. In order for this to work I changed my config/auth.php like so:
return [
'defaults' => [
'guard' => 'customer',
'passwords' => 'customers',
],
'guards' => [
'customer' => [
'driver' => 'session',
'provider' => 'customers',
],
'admin' => [
'driver' => 'session',
'provider' => 'admins',
],
'api' => [
'driver' => 'passport',
'provider' => 'admins',
],
],
'providers' => [
'customers' => [
'driver' => 'eloquent',
'model' => App\Customer::class,
],
'admins' => [
'driver' => 'eloquent',
'model' => App\Admin::class,
],
],
'passwords' => [
'customers' => [
'provider' => 'customers',
'table' => 'password_resets',
'expire' => 60,
],
'admins' => [
'provider' => 'admins',
'table' => 'password_resets',
'expire' => 60,
],
],
];
For my Customer model I set up a resource controller which is protected by a resource policy as well as the auth middleware for the index method:
namespace App\Http\Controllers;
use App\Customer;
use Illuminate\Http\Request;
class CustomerController extends Controller
{
public function __construct()
{
$this->middleware('auth:admin')->only('index');
$this->authorizeResource(Customer::class);
}
public function show(Customer $customer)
{}
...shortened
}
Here is the policy that I'm referencing in this controller:
namespace App\Policies;
use App\Customer;
use Illuminate\Auth\Access\HandlesAuthorization;
use Illuminate\Foundation\Auth\User;
class CustomerPolicy
{
use HandlesAuthorization;
public function view(User $user, Customer $customer)
{
return true;
}
}
My routes do not have any additional middleware applied.
Here is the issue:
When I'm accessing my route /customers/1 with a user of the default guard "customer" everything works as expected (no error). However when I'm trying to access that route with a admin user I'll get a 403 unauthorized response. The strange thing is that when I'm trying to check the permissions in the view with
#can('view', App\Customer::findOrFail(3))
the policy works correctly. I've found that the view method of the policy isn't being called at all when I'm accessing the route as an admin. I digged a little bit through the laravel code and I'm pretty sure that the issue is related to the fact that the customer guard is default and the user resolver only the default.
Does anyone have any idea how to solve that problem?
Thank you!
Andreas
edit:
Here is my AuthServiceProvicer.php:
namespace App\Providers;
use App\Policies\CustomerPolicy;
use App\Customer;
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
class AuthServiceProvider extends ServiceProvider
{
protected $policies = [
'App\Model' => 'App\Policies\ModelPolicy',
Customer::class => CustomerPolicy::class
];
public function boot()
{
$this->registerPolicies();
}
}
And here is my routes/web.php
Route::get('/', function () {
return view('welcome');
});
Auth::routes(['register' => false]);
Route::prefix('admin')->name('admin.')->group(function () {
Route::get('/', function () {
return redirect( route('admin.dashboard') );
});
Route::get('dashboard', 'AdminController#dashboard')->name('dashboard');
Route::get('login', 'Auth\AdminLoginController#showLoginForm')->name('login');
Route::post('login', 'Auth\AdminLoginController#login')->name('login.post');
Route::post('logout', 'Auth\AdminLoginController#logout')->name('logout');
Route::post('password/email', 'Auth\AdminForgotPasswordController#sendResetLinkEmail')->name('password.email');
Route::get('password/reset', 'Auth\AdminForgotPasswordController#showLinkRequestForm')->name('password.request');
Route::post('password/reset', 'Auth\AdminResetPasswordController#reset')->name('password.update');
Route::post('password/reset/{token}', 'Auth\AdminResetPasswordController#showResetForm')->name('password.reset');
Route::resource('customers', 'CustomerController');
});
Route::prefix('backend')->name('backend.')->group(function () {
Route::get('/', function () {
return redirect( route('backend.dashboard') );
});
Route::get('dashboard', 'BackendController#dashboard')->name('dashboard');
Route::resource('customers', 'CustomerController')->except([
'index'
]);
});
So for customers I'm using the route /backend/customer/{customer} and for admins I'm using the route /admin/customer/{customer}
After a bit of further research I came across this awesome blog post
https://medium.com/#JinoAntony/multi-user-authentication-using-guards-in-laravel-5-6-f18b4e61bdde
The important step here is to create an additional middleware "AssignGuard" that sets the guard depending on the used route.

Jwt with multiple model

I use Lavarel 5.2 framework with jwt for authorization
jwt takes user info form token just with one model,
now how can i parse user token with jwt on multiple model?
For sample when i use customer token in a api jwt parse that token from customer model , default guard should be customer
auth.php :
'defaults' => [
'guard' => 'operator',
'passwords' => 'operators',
],
'guards' => [
'operator' => [
'driver' => 'session',
'provider' => 'operators',
],
'customer' => [
'driver' => 'session',
'provider' => 'customers',
],
'biker' => [
'driver' => 'session',
'provider' => 'bikers',
]
],
'providers' => [
'operators' => [
'driver' => 'eloquent',
'model' => App\Http\Services\Auth\Model\User::class,
],
'customers' => [
'driver' => 'eloquent',
'model' => App\Http\Aggregate\Customer\Model\Customer::class,
],
'bikers' => [
'driver' => 'eloquent',
'model' => App\Http\Aggregate\Biker\Model\Biker::class,
]
],
You can create a separate middleware like AuthModel. In that you can set the config to take which providers like the below,
Config::set('auth.providers.users.model',\App\Models\Customer::class);
If you want to use multiple models, then need to use if conditions to check which url can access which models. It can be like,
if(url == '/customer/api/') {
Config::set('auth.providers.users.model',\App\Models\Customer::class);
} else if(url == '/biker/api/') {
Config::set('auth.providers.users.model',\App\Models\Biker::class);
}
In the above example, I have used url just for example, so get it from the request.
You can change the __construct function in each of your controllers as follows. So that jwt know which model to authenticate.
BikerController
function __construct()
{
Config::set('jwt.user', Biker::class);
Config::set('auth.providers', ['users' => [
'driver' => 'eloquent',
'model' => Biker::class,
]]);
}
CustomerController
function __construct()
{
Config::set('jwt.user', Customer::class);
Config::set('auth.providers', ['users' => [
'driver' => 'eloquent',
'model' => Customer::class,
]]);
}
This is my solution. Tested on Laravel 6
User Model
namespace App;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Illuminate\Database\Eloquent\SoftDeletes;
use Tymon\JWTAuth\Contracts\JWTSubject;
class User extends Authenticatable implements JWTSubject
{
use SoftDeletes;
use Notifiable;
public $incrementing = false;
protected $keyType = 'string';
protected $fillable =
[
];
protected $hidden =
[
'password',
'created_at',
'updated_at',
'deleted_at'
];
public function getJWTIdentifier()
{
return $this->getKey();
}
public function getJWTCustomClaims()
{
}
}
Teacher Model
namespace App;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Illuminate\Database\Eloquent\SoftDeletes;
use Tymon\JWTAuth\Contracts\JWTSubject;
class Teacher extends Authenticatable implements JWTSubject
{
use SoftDeletes;
use Notifiable;
public $incrementing = false;
protected $keyType = 'string';
protected $fillable =
[
];
protected $hidden =
[
'password',
'oldpassword',
'created_at',
'updated_at',
'deleted_at'
];
public function getJWTIdentifier()
{
return $this->getKey();
}
public function getJWTCustomClaims()
{
}
}
config/auth.php
'defaults' => [
'guard' => 'api',
'passwords' => 'users',
],
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
'api' => [
'driver' => 'jwt',
'provider' => 'users'
],
'teacher-api' => [
'driver' => 'jwt',
'provider' => 'teachers'
],
],
AuthController function :
if (
$request->getRequestUri() ===
'OTHER_AUTH_ROUTE'
) {
$credentials = $request->only('username', 'password']);
$token = Auth::shouldUse('teacher-api');
$token = Auth::attempt($credentials);
if (!$token) {
return response()->json(['error' => 'Unauthorized'], 401);
}
return $this->respondWithToken($token);
}
$credentials = $request->only([USERNAME, 'password']);
$token = Auth::attempt($credentials);
if (!$token) {
return response()->json(['error' => 'Unauthorized'], 401);
}
return $this->respondWithToken($token);
Hope this can help you all at future
Laravel 8 compatible
For others still looking for a clean solution:
I would suggest manually configure the providers and guards in config/auth.php and not programmatically change any providers.
The next thing to make sure the right JWTSubject auth model is used, is to create different Middleware (don't forget to specify it in Kernel.php under $routeMiddleware) for a group of routes that has to be only accessible by a specific guard/auth model. Then a middleware handle function could look like this for a Manager model:
public function handle(Request $request, Closure $next) {
if (!($request->user('managers'))) abort(401);
Auth::shouldUse('managers');
return $next($request);
}
Then create another middleware for, let's say an Employee model and change the 'managers' guard value to 'employees' which you configured in config/auth.php.
In your routes/api.php you can specify a route group using (e.g.):
Route::group(['middleware' => 'management'], function() { });
In order to make this all work correctly, specify the guard when the auth()->attempt() function is called, e.g. auth('managers')->attempt($credentials)).

Laravel 5.2 Error App\User cannot use Illuminate\Foundation\Auth\User - it is not a trait

I am pretty new to laravel 5.2. Right now I am trying to create a custom login. I created the login html. And on submit, the function shows error
App\User cannot use Illuminate\Foundation\Auth\User - it is not a trait
I couldn't find what is the error. The codes are below
Routes.php
Route::post('/', 'Admin\LoginController#postLogin');
LoginController.php
<?php
namespace App\Http\Controllers\Admin;
use App\Http\Controllers\Controller;
use Auth;
use Request;
class LoginController extends Controller {
public function index() {
return view('admin.login');
}
public function register() {
return view('admin.register');
}
public function postLogin() {
$email = Request::input('email');
$password = Request::input('password');
if (Auth::attempt(['email' => $email, 'password' => $password])) {
//echo "success";
return redirect('admin/dashboard');
} else {
return redirect('/');
}
}
}
User.php
<?php
namespace App;
use Illuminate\Foundation\Auth\User as Authenticatable;
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;
protected $table = 'users';
protected $fillable = ['name', 'email', 'password'];
protected $hidden = ['keyword', 'remember_token'];
}
Auth.php
<?php
return [
'defaults' => [
'guard' => 'web',
'passwords' => 'users',
],
'guards' => [
'web' => [
'driver' => 'session',
'provider' => 'users',
],
'api' => [
'driver' => 'token',
'provider' => 'users',
],
],
'providers' => [
'users' => [
'driver' => 'eloquent',
'model' => App\User::class,
],
'users' => [
'driver' => 'eloquent',
'model' => 'App\User',
'table' => 'users',
'password' => [
'email' => 'emails.password',
'expire' => 60,
],
],
],
'passwords' => [
'users' => [
'provider' => 'users',
'email' => 'auth.emails.password',
'table' => 'password_resets',
'expire' => 60,
],
],
];
I am following the tutorial from here
Please help me. I am stuck here from last few hours
You should use this namespace:
use Illuminate\Auth\Authenticatable;
It's a trait you should use. Now, you're trying to use a class as a trait:
use Illuminate\Foundation\Auth\User as Authenticatable;
class User {
use Authenticatable ...

Categories