Laravel 5.4: JWTAuth, ErrorException in EloquentUserProvider.php - laravel

I am a newbie of laravel, so it might be my mistake. Using laravel with tymondesigns/jwt-auth
to verify user. I am watching this tutorial Complete JWT-AUTH api with Laravel and followed every step, the tymon package installation and logging in user. But i am getting this error. I posted code below, tell me if you need more code from any other file.
ErrorException in EloquentUserProvider.php line 120: Argument 1 passed
to Illuminate\Auth\EloquentUserProvider::validateCredentials() must be
an instance of Illuminate\Contracts\Auth\Authenticatable, instance of
App\User given
This is my user model:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
class User extends Model
{
protected $hidden = ["password"];
protected $fillable = [
"id",
"name",
"password",
"mobile_number",
"gender",
"age",
"company_name",
"profile_image",
"email"
];
}
?>
This is my ApiAuthController.php
use JWTAuth;
use Illuminate\Http\Request;
use Tymon\JWTAuth\Exceptions\JWTException;
class ApiAuthController extends Controller
{
public function authenticate(){
$credentaials = request()->only('email', 'password');
print_r($credentaials);
try {
$token = JWTAuth::attempt($credentaials);
if(!$token){
return response()->json(['error'=>'invalid credentaials'], 401);
}
} catch (JWTException $e) {
return response()->json(['error'=>'something went wrong'], 500);
}
return response()->json(['token'=>$token], 200);
}
}
User store function in my UsersController:
public function store(Request $request)
{
$payload = json_decode($request->payload, true);
$validator = Validator::make($payload, $this->rules);
if ($validator->passes()) {
$user = (new User())->fill($payload);
if($user->save()){
$response = [
"msg" => "User created",
"link" => "/api/users/" . $user->id
];
return response()->json($response, 200);
}
$response = [
"msg" => "An error occured"
];
return response()->json($response, 404);
}
else {
return response()->json($validator->messages(), 404);
}
}
In storing user request, payload is key and value is json object, the small sample object is given below:
payload={
"name": "Alexa",
"email": "alexa#gmail.com",
"password":"12345",
"gender": "Male",
"age": 24
}

Add this to your model
use Illuminate\Foundation\Auth\User as Authenticatable;
and change this line
class User extends Authenticatable
Edit :
Looks like you're storing passwords in plaintext. Add this to your user model.
public function setPasswordAttribute($value)
{
$this->attributes['password'] = bcrypt($value);
}

Related

Laravel 9, Sanctum - Authenticate using a separate table for user, email & password

I've got 3 tables for Laravel authentication.
UserMeta, UserEmail and UserPassword.
We've set it up this way so users can add multiple emails to their account, we can track password changes (&revert if necessary).
This obviously makes authentication a bit tricky and I'm wondering how I'd go about this?
I've tried making a custom Auth::attempt and it does seem to log the user in, but when I'm checking the guard via a route I get the error:
"message": "Object of type Illuminate\\Auth\\AuthManager is not callable",
when trying to access a auth:sanctum guarded route (like using the code below)
Route::group(['middleware' => ['auth:sanctum']], function () {
Route::get('/account/me', function (\Illuminate\Http\Request $request) {
return $request->user();
});
});
Here is my LoginController.php
public function authenticate(Request $request)
{
$authenticate = new Authenticate;
$returnArray = [
'success' => false,
'message' => null,
'userId' => null,
'token' => null,
];
if (Auth::check()) {
$returnArray['message'] = 'ALREADY_LOGGED_IN';
$returnArray['userId'] = Auth::id();
} else {
$authAttempt = $authenticate->auth($request->emailAddress, $request->password)['success'];
if ($authAttempt) {
$token = $request->user()->createToken('USER AUTHENTICATION TOKEN', ['*']);
$returnArray['message'] = 'SUCCESS';
$returnArray['success'] = true;
$returnArray['userId'] = $request->user()->id;
$returnArray['token'] = $token->plainTextToken;
} else {
$returnArray['message'] = 'Invalid email address or password.';
}
}
return $returnArray;
}
And when I hit the login route:
{
"success": true,
"message": "SUCCESS",
"userId": 1,
"token": "10|0fgn5XfZyaIuaLOxOOSkIqQdqplc8G1y7SLUKyzD"
}
which does insert into the database.
Auth:
'providers' => [
'users' => [
'driver' => 'eloquent',
'model' => \App\Models\User\UserMeta::class,
],
Models:
App\Models\User\UserMeta:
<?php
namespace App\Models\User;
use App\Models\BaseAuthenticatableModel;
use App\Models\BaseModel;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
use Laravel\Sanctum\HasApiTokens;
class UserMeta extends BaseAuthenticatableModel
{
use HasApiTokens, HasFactory, Notifiable;
protected $table = 'UserMeta';
public function emailAddressList()
{
return $this->hasMany(UserEmail::class);
}
public function emailAddressLatest()
{
return $this->hasMany(UserEmail::class)->latest()->emailAddress;
}
public function passwordList()
{
return $this->hasMany(UserPassword::class);
}
public function passwordLatest()
{
return $this->hasMany(UserPassword::class)->latest()->value;
}
UserPassword:
<?php
namespace App\Models\User;
use App\Models\BaseModel;
class UserPassword extends BaseModel
{
protected $table = 'UserPassword';
public function user()
{
return $this->belongsTo(UserMeta::class);
}
}
UserEmail
<?php
namespace App\Models\User;
use App\Models\BaseModel;
class UserEmail extends BaseModel
{
protected $table = 'UserEmail';
public function user()
{
return $this->belongsTo(UserMeta::class);
}
}
I've been stuck on this for a few days - tried using Passport, JWT & Sanctum but I'm now really at a loss.
Thank you

How to Create Model with Notifiable Trait

I want create a Model with Notifiable feature,
First,in my controller :
$collection = collect([
[
'name' => 'user1',
'email' => 'user1#gmail.com',
],
[
'name' => 'user2',
'email' => 'user2#gmail.com',
],
[
'name' => 'user1000',
'email' => 'user1000#gmail.com',
],
]);
$u3 = new User3($collection);
when I return $u3->getEmailList(); , output is :
[{"name":"user1","email":"user1#gmail.com"},{"name":"user2","email":"user2#gmail.com"},{"name":"user1000","email":"user1000#gmail.com"}]
my class for User3 is:
namespace App;
use App\User;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Notifications\Notifiable;
use Illuminate\Support\Facades\Notification;
use Illuminate\Notifications\RoutesNotifications;
use Notifications\EmailClientOfAccount;
class User3 extends User
{
use Notifiable;
public $emailList;
public function __construct($emails)
{
$this->emailList = $emails;
}
public function getEmailList()
{
return $this->emailList;
}
public function routeNotificationForMail($notification)
{
return $this->emailList['email'];
}
}
Then, I pass $u3 to Notification as:
Notification::send($u3->getEmailList(), new
SendMailNotification($template,$subject,$request->input('mailFromTitle'),$attachments));
It show below error:
Symfony\Component\Debug\Exception\FatalThrowableError: Call to a member function routeNotificationFor() on array
can you help me for solve this problem,Please?
Thanks in Advance,
//-------------------
I correct to :
Notification::send($u3, new SendMailNotification($template,$subject,$request->input('mailFromTitle'),$attachments));
In my My Notification:
public function toMail($notifiable)
{
return new EmailTo($notifiable,$this->view,$this->topic,$this-
>mailFrom,$this->attaches);
}
and in Build():
public function build()
{
$email= $this->view($this->view);
return $email;
}
But it not work, I dont know where is mistake?
Notification send expects a Notifiable object, not the email list itself, if you change it to this, you should get further.
Notification::send($u3, new SendMailNotification($template,$subject,$request->input('mailFromTitle'),$attachments));

How to receive JSON from POST?

I receive JSON from Vue.JS client via REST Api, and I'd like to get data using Eloquent, but it doesn't work. It's not blade and not standard form-submit data, I receive JSON Api from client, single-page application.
This is the JSON, addressed to route '/order' from client, method POST:
{
"name": "John",
"phone": "+7 794 910 5708",
"email": "example#gmail.com"
}
The route is:
Route::post('/order','OrderController#order');
In a Controller I try to do that:
<?php
namespace App\Http\Controllers;
use Request;
use App\Data;
class OrderController extends Controller
{
public function order()
{
$input = Request::all();
$data = new Data;
$data->name = $input['name'];
$data->phone = $input['phone'];
$data->save();
return response()->json(['result' => '200 OK'], 200);
}
}
But nothing happens. What is the right syntax to receive data from REST Api?
Make some changes as per below:
In controller:
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Data;
class OrderController extends Controller
{
public function order(Request $request)
{
$post = $request->all();
$data = Data::create($post);
if($data){
return response()->json(['success' => true, 'message' => 'Data has been inserted!']);
} else {
return response()->json(['success' => false, 'message' => 'Data not inserted, Something went wrong!']);
}
}
}

Error in Laravel Accessor while retrieving date in specific format

I am using Laravel accessor to access value of date field in specific format. But, I am getting error from carbon library of InvalidArgument. Below is my code.
<?php
namespace App\modules\hrm;
use App\Helper\DateFormat;
use Illuminate\Database\Eloquent\Model;
class Holiday extends Model
{
protected $guarded = [];
protected $dates = ['off_date'];
public function setOffDateAttribute($date)
{
$this->attributes['off_date'] = DateFormat::convertToDBFormat($date);
}
public function getOffDateAttribute($date){
return DateFormat::convertToUIFormat($date);
}
}
Helper File
<?php
namespace App\Helper;
use Carbon\Carbon;
class DateFormat
{
public static function convertToDBFormat($date) {
return Carbon::createFromFormat('d/m/Y', $date)->format('Y-m-d');
}
public static function convertToUIFormat($date) {
return Carbon::createFromFormat('Y-m-d', $date)->format('d/m/Y');
}
}
?>
Model Function
public function show(Request $request)
{
$data = Holiday::find(json_decode($request->get('data'),true)['id']);
if (empty($data)) {
return response()->json(array("status" => "error", "message" => "Invalid ID"));
} else {
return response()->json(array("status" => "success", "data" => $data));
}
}
I am getting error from Carbon but I think I am doing something wrong while sending those values, maybe i am not using the laravel accessor feature properly.
Error:
"message": "Trailing data",
"exception": "InvalidArgumentException",

Argument 1 passed to Illuminate\Auth\Guard::login() must implement interface Illuminate\Auth\UserInterface, null given open:

I have facebook login which uses socialite library. The error in the question occurs when the callback occurs.
Here is my "USER" model
<?php
namespace App;
use Illuminate\Contracts\Auth\Authenticatable;
use Illuminate\Database\Eloquent\Model;
class User extends Model implements Authenticatable
{
//use Illuminate\Contracts\Auth\Authenticatable;
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $fillable = [
'name', 'email', 'password',
];
/**
* The attributes that should be hidden for arrays.
*
* #var array
*/
protected $hidden = [
'password', 'remember_token',
];
use \Illuminate\Auth\Authenticatable;
public function posts()
{
return $this->hasMany('App\Post');
}
public function likes()
{
return $this->hasMany('App\Like');
}
}
The Socialite logins are handled by SocialAuthController and what i understood from the error is , auth()->login($user); , null is passed to the login("NULL"). Here is the code of SocialAuthController. What's the mistake i have made here and how to fix this. thanks in advance
<?php
namespace App\Http\Controllers;
use Illuminate\Contracts\Auth\Authenticatable;
use Illuminate\Http\Request;
use App\Http\Requests;
use App\Http\Controllers\Controller;
use Socialite;
use App\SocialAccountService;
class SocialAuthController extends Controller
{
public function redirect($provider)
{
return Socialite::driver($provider)->redirect();
}
use \Illuminate\Auth\Authenticatable;
public function callback(SocialAccountService $service , $provider)
{
$user = $service->createOrGetUser(Socialite::driver($provider));
auth()->login($user);
return redirect()->to('/home');
}
}
The below is the handling service that will try to register user or log in if account already exists.
Here is the code of SocialAccountService.php
<?php
namespace App;
use Laravel\Socialite\Contracts\Provider;
class SocialAccountService
{
public function createOrGetUser(Provider $provider)
{
$providerUser = $provider->user();
$providerName = class_basename($provider);
$account = SocialAccount::whereProvider($providerName)
->whereProviderUserId($providerUser->getId())
->first();
if ($account) {
return $account->user;
} else {
$account = new SocialAccount([
'provider_user_id' => $providerUser->getId(),
'provider' => $providerName
]);
$user = User::whereEmail($providerUser->getEmail())->first();
if (!$user) {
$user = User::create([
'email' => $providerUser->getEmail(),
'name' => $providerUser->getName(),
]);
}
$account->user()->associate($user);
$account->save();
return $user;
}
}
}
This will try to find provider's account in the system and if it is not present it will create new user. This method will also try to associate social account with the email address in case that user already has an account.
My wild guess is that createOrGetUser() returns NULL because the SocialAccount does not have a user. So what could do is change the if condition in that method to check if the $account has a user:
public function createOrGetUser(Provider $provider)
{
...
if ( $account && property_exists($account, 'user') && $account->user ) {
return $account->user;
} else {
...

Resources