I'm trying to generate a token to authenticate users in my Controller the following way:
namespace App\Http\Controllers\API;
use Illuminate\Foundation\Auth\AuthenticatesUsers;
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use Illuminate\Support\Facades\Auth;
use App\Models\User;
class AuthController extends Controller
{
public function login()
{
if (Auth::attempt(['email' => request('email'), 'password' => request('password')])) {
$user = Auth::user();
$success['token'] = $user->createToken('myApp')->accessToken;
dd($success['token']);
}
}
Currently, I'm just trying to print out the token. And this is my User's model:
<?php
namespace App\Models;
use Illuminate\Notifications\Notifiable;
//use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Support\Facades\Hash;
use Laravel\Passport\HasApiTokens;
class User extends Authenticatable
{
use HasApiTokens, Notifiable;
const USER_FIRST_NAME_FIELD = "first_name";
const USER_LAST_NAME_FIELD = "last_name";
const USER_PREFERRED_NAME_FIELD = "preferred_name";
const USER_EMAIL_FIELD = "email";
const USER_EMAIL_VERIFIED_AT_FIELD = "email_verified_at";
const USER_PASSWORD_FIELD = "password";
const USER_REMEMBER_TOKEN_FIELD = "remember_token";
const USER_RECEIVE_NEWSLETTER_FIELD= "receive_newsletter";
const USER_ACTIVE_FIELD = "active";
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $fillable = [
self::USER_FIRST_NAME_FIELD,
self::USER_LAST_NAME_FIELD,
self::USER_PREFERRED_NAME_FIELD,
self::USER_EMAIL_FIELD,
self::USER_PASSWORD_FIELD,
self::USER_RECEIVE_NEWSLETTER_FIELD,
self::USER_ACTIVE_FIELD,
];
/**
* The attributes that should be hidden for arrays.
*
* #var array
*/
protected $hidden = [
self::USER_PASSWORD_FIELD,
self::USER_REMEMBER_TOKEN_FIELD
];
/**
* Automatically creates password hash when password is submitted
*
* #param string $password
* #return void
*/
public function setPasswordAttribute(string $password) : void
{
$this->attributes['password'] = Hash::make($password);
}
}
As you can see I'm using HasApiTokens, Notifiable traits and nonetheless I'm getting an error from my controller saying:
Call to undefined method App\User::createToken()
Passport is installed and configured correctly.
Here's something weird:
When registering an user (I'm using a separate controller and also using a service) a token is created successfully:
Here's my controller:
<?php
namespace App\Http\Controllers\API;
use App\Services\UserService;
use Illuminate\Http\JsonResponse;
use App\Http\Controllers\Controller;
use App\Http\Requests\RegisterUserRequest;
class UserController extends Controller
{
private $user;
public function __construct(UserService $user)
{
$this->user = $user;
}
public function store(RegisterUserRequest $request) : JsonResponse
{
// TODO: verify message on error
$user = $this->user->register($request->validated());
$token = $user->createToken('MyApp')->accessToken;
dd($token);
return response()->json(['status' => 201, 'user_id' => $user->id]);
}
}
Here's my service:
<?php
namespace App\Services;
use App\Models\User;
use App\Services\BaseServiceInterface;
class UserService implements BaseServiceInterface
{
public function register(array $formValues) : User
{
// 'terms and conditions' should not be saved into the db, hence it's removed
unset($formValues['terms_conditions']);
return User::create($formValues);
}
}
and here's my model again:
<?php
namespace App\Models;
use Illuminate\Notifications\Notifiable;
//use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Support\Facades\Hash;
use Laravel\Passport\HasApiTokens;
class User extends Authenticatable
{
use HasApiTokens, Notifiable;
const USER_FIRST_NAME_FIELD = "first_name";
const USER_LAST_NAME_FIELD = "last_name";
const USER_PREFERRED_NAME_FIELD = "preferred_name";
const USER_EMAIL_FIELD = "email";
const USER_EMAIL_VERIFIED_AT_FIELD = "email_verified_at";
const USER_PASSWORD_FIELD = "password";
const USER_REMEMBER_TOKEN_FIELD = "remember_token";
const USER_RECEIVE_NEWSLETTER_FIELD= "receive_newsletter";
const USER_ACTIVE_FIELD = "active";
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $fillable = [
self::USER_FIRST_NAME_FIELD,
self::USER_LAST_NAME_FIELD,
self::USER_PREFERRED_NAME_FIELD,
self::USER_EMAIL_FIELD,
self::USER_PASSWORD_FIELD,
self::USER_RECEIVE_NEWSLETTER_FIELD,
self::USER_ACTIVE_FIELD,
];
/**
* The attributes that should be hidden for arrays.
*
* #var array
*/
protected $hidden = [
self::USER_PASSWORD_FIELD,
self::USER_REMEMBER_TOKEN_FIELD
];
As I told you, when creating a user the token is being generated correctly.
I'd say that Auth::user() is not calling my Model directly, but I don't know for sure that's what is happening.
Any idea why?
Thanks
Since your guard is returning the wrong User model, App\User, you should check your auth configuration, 'config/auth.php'. In the providers array adjust any provider, usually users, that is using the App\User model to App\Models\User instead.
'providers' => [
'users' => [
'driver' => 'eloquent',
// 'model' => App\User::class,
'model' => App\Models\User::class,
],
...
],
in my case, i missed to use Trait HasApiTokens
thats why laravel was unable to create tokens.
just open User.php
afetr name space include
use Laravel\Passport\HasApiTokens;
then inside class
use HasApiTokens
Pls note : I am using laravel 7.
So, this is not the right way to do it but it's working at the moment:
<?php
namespace App\Http\Controllers\API;
use App\Models\User;
use Illuminate\Support\Facades\Auth;
use App\Http\Controllers\API\BaseController;
class AuthController extends BaseController
{
public function login()
{
if (Auth::attempt(['email' => request('email'), 'password' => request('password')])) {
$authenticated_user = \Auth::user();
$user = User::find($authenticated_user->id);
dd($user->createToken('myApp')->accessToken);
}
dd('here');
}
}
Now I'm seeing the token.
I wanna do it the right way so I still would appreciate if any one could help me.
Thanks
you can let the auth.basic middleware do the authentication for you, by calling it in the construct method:
public function __construct()
{
$this->middleware('auth.basic');
}
Then generate the access token for the currently authenticated user, and return the user information along with the access token:
public function login()
{
$Accesstoken = Auth::user()->createToken('Access Token')->accessToken;
return Response(['User' => Auth::user(), 'Access Token' => $Accesstoken]);
}
Now the Controller will look like this:
<?php
namespace App\Http\Controllers\API;
use App\Models\User;
use Illuminate\Support\Facades\Auth;
use App\Http\Controllers\API\BaseController;
class AuthController extends BaseController
{
/**
* Instantiate a new controller instance.
*
* #return void
*/
public function __construct()
{
$this->middleware('auth.basic');
}
public function login()
{
$Accesstoken = Auth::user()->createToken('Access Token')->accessToken;
return Response(['User' => Auth::user(), 'Access Token' => $Accesstoken]);
}
}
i have updated laravel 6 to 8 & i am using sanctum for API auth.
This works for me when i want to get token for API auth.
in User model
use Laravel\Sanctum\HasApiTokens;
and use the traits in function
use HasApiTokens
Model/User.php
<?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\Sanctum\HasApiTokens;
use Hash;
class User extends Authenticatable
{
use HasApiTokens, HasFactory, Notifiable;
/**
* The attributes that are mass assignable.
*
* #var string[]
*/
protected $fillable = [
'name',
'email',
'password',
'status'
];
/**
* The attributes that should be hidden for serialization.
*
* #var array
*/
protected $hidden = [
'password',
'remember_token',
];
/**
* The attributes that should be cast.
*
* #var array
*/
protected $casts = [
'email_verified_at' => 'datetime',
];
public function setPasswordAttribute($input)
{
if ($input) {
$this->attributes['password'] = app('hash')->needsRehash($input) ? Hash::make($input) : $input;
}
}
public function roles()
{
return $this->belongsToMany(Role::class);
}
public function scopeActive($query){
return $query->where('status', 'ACTIVE');
}
}
Related
I have an Vue + Laravel application. Here I am using laravel API routes to get the data. For the API auth I am using JWT from this tutorial: https://blog.logrocket.com/implementing-jwt-authentication-laravel-9/
Now I am getting:
{"message":"Unauthenticated."}
error message whne I access to this API route: http://localhost:3000/api/countries
Country.php (Model)
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Factories\HasFactory;
class Country extends Model
{
use HasFactory;
protected $table = 'countries';
protected $primaryKey = 'id_country';
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $fillable = [
'country_name' ,
'code' ,
];
}
CountryController.php (Controller)
<?php
namespace App\Http\Controllers;
use App\Models\Country;
use Illuminate\Http\Request;
class CountryController extends Controller
{
public function __construct()
{
$this->middleware('auth:api');
}
/**
* #return \Illuminate\Http\JsonResponse
*/
public function countries()
{
$country = Country::get();
return response()->json($country, 200);
}
}
api.php
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Route;
use App\Http\Controllers\Auth\AuthController;
use App\Http\Controllers\CountryController;
Route::controller(CountryController::class)->group(function () {
Route::get('countries', 'countries')->name("countries");
});
Can you tell me what is wrong here and how can I solve it?
I'm building a laravel project which is a community platform, so it's gonna need a follower logic (pretty similar to twitter, instagram, etc).
I already created the logic for authentication and profile, but, when researching and writing the code for the followers state and check if the user is following someone, i got the functions on my model, which now is something like:
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\Sanctum\HasApiTokens;
class User extends Authenticatable
{
use HasApiTokens, HasFactory, Notifiable;
/**
* The attributes that are mass assignable.
*
* #var array<int, string>
*/
protected $fillable = [
'name',
'email',
'password',
'phone',
'description',
'profilepicture',
'status',
];
/**
* The attributes that should be hidden for serialization.
*
* #var array<int, string>
*/
protected $hidden = [
'password',
'remember_token',
];
/**
* The attributes that should be cast.
*
* #var array<string, string>
*/
protected $casts = [
'email_verified_at' => 'datetime',
];
public function following()
{
return $this->belongsToMany('App\Models\User', 'followers', 'follower_user_id', 'user_id')->withTimestamps();
}
public function isFollowing(User $user)
{
return !is_null($this->following()->where('user_id', $user->id)->first());
}
}
And on my Profile Controller, I have:
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use App\Models\User;
class Profile extends Controller
{
public function show($id)
{
$user = User::where('id', $id)->firstOrFail();
$me = Auth::user();
$is_edit_profile = (Auth::id() == $user->id);
$is_follow_button = (!$is_edit_profile) && (!$me->isFollowing($user));
return view('profile', ['user' => $user, 'is_edit_profile' => $is_edit_profile, 'is_follow_button' => $is_follow_button]);
}
}
But VSCode says that i have a undefined method isFollowing in my controller, in the line:
$is_follow_button = (!$is_edit_profile) && (!$me->isFollowing($user));
Someone have a clue of why is this happening?
I'm using Laravel 8.
It's one of my first big projects, so previously sorry for any rookie mistake.
Thanks for your time and help!
Auth::user() returns an object of type Illuminate\Contracts\Auth\Authenticatable which does not implement isFollowing
Option 1 : You can add #var annotation to specify the type of your object
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use App\Models\User;
class Profile extends Controller
{
public function show($id)
{
$user = User::where('id', $id)->firstOrFail();
/** #var User $me */
$me = Auth::user();
$is_edit_profile = (Auth::id() == $user->id);
$is_follow_button = (!$is_edit_profile) && (!$me->isFollowing($user));
return view('profile', ['user' => $user, 'is_edit_profile' => $is_edit_profile, 'is_follow_button' => $is_follow_button]);
}
}
Option 2 : You can extends the Auth facade by creating a new facade with the expected return type :
namespace App\Extensions\Facades;
use App\Models\User;
/**
* #method static User user()
*/
class Auth extends \Illuminate\Support\Facades\Auth
{
}
And then you can use this facade instead of the previous one
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use App\Extensions\Facades\Auth;
use App\Models\User;
class Profile extends Controller
{
public function show($id)
{
$user = User::where('id', $id)->firstOrFail();
$me = Auth::user();
$is_edit_profile = (Auth::id() == $user->id);
$is_follow_button = (!$is_edit_profile) && (!$me->isFollowing($user));
return view('profile', ['user' => $user, 'is_edit_profile' => $is_edit_profile, 'is_follow_button' => $is_follow_button]);
}
}
I am trying ORM one to one relationship. I dont know why it cant recognize model class phone.
code as follows.
Phone.php
<?php
namespace App\Models;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Relations\HasOne;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
class User extends Authenticatable
{
use HasFactory, Notifiable;
/**
* 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',
];
/**
* The attributes that should be cast to native types.
*
* #var array
*/
protected $casts = [
'email_verified_at' => 'datetime',
];
public function Phone(){
return $this->hasOne('app\Models\Phone');
}
}
Phone.php
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Phone extends Model
{
use HasFactory;
protected $table = "phones";
public function User(){
return $this->belongsTo('app\Models\User');
}
}
UserController.php
<?php
namespace App\Http\Controllers;
use App\Models\Phone;
use App\Models\User;
use Illuminate\Http\Request;
class UserController extends Controller
{
public function insert(){
$user = new User();
$user->name = 'BBB';
$user->email = 'bbb#mail.com';
$user->password = 'bbb#mail.com';
$user->save();
$phone = new Phone();
$phone->number = "445566";
$user->Phone()->save($phone);
return "RECORDS ADDED";
}
public function show($id){
$phone = User::find($id)->phone;
return $phone;
}
}
web.php
<?php
use Illuminate\Support\Facades\App;
use Illuminate\Support\Facades\Route;
Route::get('/', function () {
return view('welcome');
});
Route::get('insert',[\App\Http\Controllers\UserController::class,'insert'])->name('user.insert');
Route::get('show/{id}',[\App\Http\Controllers\UserController::class,'show'])->name('user.show');
You need to fix this
public function User(){
return $this->belongsTo('App\Models\User');
}
here fix namespace app to App like that you need to fix all
namespace App\Models;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Relations\HasOne;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Notifications\Notifiable;
class User extends Authenticatable
{
use HasFactory, Notifiable;
/**
* 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',
];
/**
* The attributes that should be cast to native types.
*
* #var array
*/
protected $casts = [
'email_verified_at' => 'datetime',
];
public function Phone(){
return $this->hasOne('App\Models\Phone');
//Better to use ::class notation for greater benefits with IDE
//return $this->hasOne(Phone::class);
}
}
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
class Phone extends Model
{
use HasFactory;
protected $table = "phones";
public function User(){
return $this->belongsTo('App\Models\User');
//Better to use ::class notation for greater benefits with IDE
//return $this->hasOne(User::class);
}
}
Folder/directory is app but the namespace is App
So need to change app\Models\Phone and app\Models\User to App\Models\Phone and App\Models\User
Better yet, use ::class notation for greater benefits with IDE - like easy navigation - not possible with string literals.
So instead of string literal App\Models\Phone import use App\Models\Phone statement and the Phone::class
Similarly for User import use App\Models\User and then use User::class
I made a socialite login using Google and Facebook, but in the SocialiteController section there is an error like the question above.
this is my SocialiteController
use Illuminate\Http\Request;
use App\Http\Controllers\Controller;
use Laravel\Socialite\Facades\Socialite;
use Illuminate\Support\Facades\Auth;
use Spatie\Permission\Models\Role;
use App\SocialAccount;
use App\User;
class SocialiteController extends Controller
{
public function redirectToProvider($provider)
{
return Socialite::driver($provider)->redirect();
}
public function handleProviderCallback($provider)
{
$user = Socialite::driver($provider)->user();
$authUser = $this->findOrCreateUser($user, $provider);
Auth::login($authUser, true);
return redirect('/personal');
}
public function findOrCreateUser($socialUser, $provider)
{
$socialAccount = SocialAccount::where('provider_id', $socialUser->getId())
->where('provider_name', $provider)
->first();
if($socialAccount) {
return $socialAccount->user;
} else {
$user = User::where('email', $socialUser->getEmail())->first();
if(!$user) {
$user = User::create([
'username' => $socialUser->getName(),
'email' => $socialUser->getEmail()
]);
$user->assignRole('Registered');
}
$user->socialAccounts()->create([
'provider_id' => $socialUser->getId(),
'provider_name' => $provider
]);
return $user;
}
}
}
this is my User model
<?php
namespace App;
use Illuminate\Notifications\Notifiable;
use Illuminate\Contracts\Auth\MustVerifyEmail;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Spatie\Permission\Traits\HasRoles;
use App\Profile;
use App\Article;
use App\Video;
use App\Images;
use App\News;
class User extends Authenticatable Implements MustVerifyEmail
{
use Notifiable, HasRoles;
protected $table = "users";
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $fillable = [
'username', 'email', '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',
];
public function profile(){
return $this->hasOne(Profile::class);
}
public function article()
{
return $this->hasMany(Article::class);
}
public function socialAccounts()
{
return $this->hasOne(SocialAccount::class);
}
public function video(){
return $this->hasMany(Video::class);
}
public function news(){
return $this->hasMany(News::class);
}
}
the complete error message like this :
Argument 1 passed to Illuminate\Auth\SessionGuard::login() must implement interface Illuminate\Contracts\Auth\Authenticatable, null given, called in /home/asyj6686/public_html/sublaravel/vendor/laravel/framework/src/Illuminate/Auth/AuthManager.php on line 297
Argument 1 passed to Illuminate\Auth\SessionGuard::login() must implement interface Illuminate\Contracts\Auth\Authenticatable, null given
This error is pretty straight-forward. It means that you have passed a null value to the login.
Auth::login($authUser, true);
I don't see anything wrong with the provided code. Therefore, I'm going to guess that you may have simply forgotten to add the inverse relationship with User in the SocialAccount model. This would cause $socialAccount->user to return null and generate the error you are receiving.
App\SocialAccount.php
class SocialAccount extends Model
{
// ...
public function user()
{
return $this->belongsTo(User::class);
}
}
On a side note, shouldn't a User be able to ->hasMany() SocialAccounts?
When I successfully login there is no problem I just get logged in. But when I type the wrong credentials it gives me this error:
Type error: Argument 1 passed to Illuminate\Auth\SessionGuard::login()
must implement interface Illuminate\Contracts\Auth\Authenticatable,
null given, called in
C:\xampp\htdocs\project\vendor\laravel\framework\src\Illuminate\Auth\AuthManager.php
on line 294
This is my login controller:
<?php
namespace App\Http\Controllers\Auth;
use \Auth;
use App\Http\Controllers\Controller;
use Illuminate\Foundation\Auth\AuthenticatesUsers;
use Illuminate\Http\Request;
use App\Account;
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;
/**
* Where to redirect users after login.
*
* #var string
*/
protected $redirectTo = '/home';
/**
* Create a new controller instance.
*
* #return void
*/
public function __construct()
{
$this->middleware('guest', ['except' => 'logout']);
}
public function login()
{
$user = Account::where('email', request()->email)
->where('password',bcrypt(request()->password))
->first();
Auth::login($user);
return redirect('/');
}
}
My Account (user) model:
<?php
namespace App;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Notifications\Notifiable;
use Illuminate\Foundation\Auth\User as Authenticatable;
use Illuminate\Auth\Authenticatable as AuthenticableTrait;
class Account extends Authenticatable
{
use Notifiable;
use AuthenticableTrait;
public $timestamps = false;
/**
* The attributes that are mass assignable.
*
* #var array
*/
protected $fillable = [
'username', 'email', 'password',
];
/**
* The attributes that should be hidden for arrays.
*
* #var array
*/
protected $hidden = [
'password', 'remember_token',
];
}
What am I doing wrong?