I implement socialite together with manual registration where register using facebook is a user's option. but i noticed that if the user registered first with the manual registration and logout then came back and register using facebook it produce an error
SQLSTATE[23000]: Integrity constraint violation: 1062 Duplicate entry"
here is my current UserRepository
namespace App\Repositories;
use App\User;
class UserRepository{
public function findByUsernameOrCreate($userData)
{
return User::firstOrCreate([
'first_name' => $userData->first_name,
'last_name' => $userData->last_name,
'email' => $userData->email
]);
}
}
I recently had this issue. I was testing a pre registered user's ability to login with facebook and have their avatar and email updated when they did.
Assuming you can check for existing (non facebook) user by their email address.
$user = User::where('email', $userData->email)->first();
if ($user){
// Update existing user with facebook data.
$user->email = $userData->email;
// Any other fields you want to update.
$user->avatar = $userData->avatar;
$user->save();
return $user;
}
Then your original function here.
Mark is right, however the data will be updated each time the user connect with Facebook. Here's some improvements :
$authUser = User::where('email', $existingUser->email)->first();
if ($authUser){
// Check and update if Facebook data doesn't exists
if(!($authUser->facebook_id)){
$authUser->facebook_id = $existingUser->id;
$authUser->avatar = $existingUser->avatar;
$authUser->save();
}
return $authUser;
}
// following by your function here...
Related
My registration form additionally accepts the name of the user's company, which I want to insert in a separate table "Holdings". All data is successfully saved to the Holdings and Users table, but an error occurs at the last step when redirecting to the home page.
ResgisterController:
protected function create(array $data)
{
//Mail::to($data['email'])->send(new Welcome($data['name']));
$id = User::insertGetId([
'name' => $data['name'],
'email' => $data['email'],
'password' => Hash::make($data['password']),
'role' => 8
]);
$oHolding = new Holdings;
$oHolding->shortname = $data['orgname'];
$oHolding->creator = $id;
$oHolding->save();
DB::table('users')->where('id', $id)->update([
'holding_id' => $oHolding->id,
]);
$user = DB::table('users')->select('*')->where('id', $id)->get();
return $user;
}
Error Message:
Argument 1 passed to Illuminate\Auth\SessionGuard::login() must implement interface Illuminate\Contracts\Auth\Authenticatable, instance of Illuminate\Support\Collection given, called in /Users/admin/Sites/jetime/vendor/laravel/framework/src/Illuminate/Foundation/Auth/RegistersUsers.php on line 35
Login Function
public function login(AuthenticatableContract $user, $remember = false)
{
$this->updateSession($user->getAuthIdentifier());
// If the user should be permanently "remembered" by the application we will
// queue a permanent cookie that contains the encrypted copy of the user
// identifier. We will then decrypt this later to retrieve the users.
if ($remember) {
$this->ensureRememberTokenIsSet($user);
$this->queueRecallerCookie($user);
}
// If we have an event dispatcher instance set we will fire an event so that
// any listeners will hook into the authentication events and run actions
// based on the login and logout events fired from the guard instances.
$this->fireLoginEvent($user, $remember);
$this->setUser($user);
}
I will be glad of any help, how to fix the error?
You are returning a collection rather than an instance of a class that implements Authenticatable.
You can see this happening here:
$user = DB::table('users')->select('*')->where('id', $id)->get();
return $user;
If you have the User model that ships with Laravel, then you'll actually want to do:
$user = User::find($id);
return $user;
Although your whole create method could be cleaned up to streamline all of this, however that isn't the topic of your question.
I want to have the registration after the auth, so the admin could create a user.I tried to find something about that but all examples are in Laravel 5s and the methodes of the controllers aren't the same.
Have you an idea,please?
If you want to create a new user as an admin, you just have to use the User::create([ ... ]) method. Remeber to put an email and a hashed password, such that the user can log in.
Example for user creation:
User::create([
'email' => 'foo#bar.com',
'password' => bcrypt('foobar'),
]);
If you want to remove the registration for guests, you should remove the RegistrationController and change the route to Auth::routes(['register' => false]);.
Its common for administrators to create users for their application. You have to be carefull with the creating of user. I personally dont want a administrator that creates a password for my account.
I would do the following:
1.Create a user with a temporary password.
public function create(){
$user = new User();
$user->name = $request->name;
$user->email = $request->email;
$user->password = Hash::make(Str::random(32));
$user->regToken = Str::random(32);
}
2.Save the user with a temporary password and send a registration email to the new user so he can change his password.
$user->notify(new MailCompleteRegistrationNotification($user->regToken, $user->email));
I use mail notifications to send the registration mail. in the notification i have the following tomail function.
public function toMail($notifiable)
{
return (new MailMessage)
->subject("Subject")
->line('Welcome to the application. We created a account for you but still need some details.')
->line('If you want to complete the registration you can click the button below:')
->action('Complete registration', url('registration', [$this->regToken, $this->email]));
}
I would recommend doing the user creation like that
In a laravel 5.8 API project, I want users to login via their social accounts. So far I have been able to use Socialite to retrieve user info from the provider and use it to create a new user record. But when I try to have the user log in again, it throws up the following error
Call to undefined method Laravel\Socialite\Two\User::createToken()
Here's the code I am working with
<?php
namespace App\Http\Controllers;
use App\User;
use Socialite;
use App\SocialAccount;
use App\Http\Resources\UserResource;
class SocialAuthController extends Controller
{
...
public function handleProviderCallback($provider)
{
$socialUser = Socialite::driver($provider)->stateless()->user();
$userSocialAccount = SocialAccount::where('provider_id', $socialUser->id)->where('provider_name', $provider)->first();
/*
if account exist, return the social account user
else create the user account, then return the new user
*/
if ($userSocialAccount) {
// generate access token for use
$token = $socialUser->createToken('********')->accessToken;
// return access token & user data
return response()->json([
'token' => $token,
'user' => (new UserResource($userSocialAccount))
]);
} else {
$user = User::create([
'firstname' => $socialUser->name,
'lastname' => $socialUser->name,
'username' => $socialUser->email,
'email_verified_at' => now()
]);
if ($user) {
SocialAccount::create([
'provider_id' => $socialUser->id,
'provider_name' => $provider,
'user_id' => $user->id
]);
}
// assign passport token to user
$token = $user->createToken('********')->accessToken;
return response()->json(['token' => $token, 'user' => new UserResource($user)]);
}
}
}
I haven't been able to spot the reason why I am getting the error when the user attempts a second login but there is no error if it's the first time the user logs in with a social account.
Why does it complain about Laravel\Socialite\Two\User::createToken() method? If I try adding this line use Laravel\Socialite\Two\User vscode intelephsense flags it as a duplicate of App\User so what is really going on in my code?
I think your last sentence hits the problem: the Laravel\Socialite\Two\User and App\User are two fully separate entities.
The Socialite::driver($provider)->stateless()->user() provides you with a Socialite User whereas User::create creates an App\User.
The second $token = $user->createToken('********')->accessToken; works because App\User has the createToken function and the other does not.
First of all the problem I was having with having a token generated by passport for users authentication after the first social login was because I was calling the createToken method on the user returned by Socialite. As explained by #JorisJ1 Socialite does not have the createToken function so my initial code threw an error.
Here's how I fixed it
public function handleProviderCallback($provider)
{
// retrieve social user info
$socialUser = Socialite::driver($provider)->stateless()->user();
// check if social user provider record is stored
$userSocialAccount = SocialAccount::where('provider_id', $socialUser->id)->where('provider_name', $provider)->first();
if ($userSocialAccount) {
// retrieve the user from users store
$user = User::find($userSocialAccount->user_id);
// assign access token to user
$token = $user->createToken('Pramopro')->accessToken;
// return access token & user data
return response()->json([
'token' => $token,
'user' => (new UserResource($user))
]);
} else {
...
}
}
Comments are welcomed if there is a better way for adding social authentication to API.
I am trying to set up Socialite in Laravel for facebook logging. I got user logged in , but now I have a problem storing the details in the database.
Also I would like to know how to notice my app that User is logged in? For normal loggin I used native AuthController and everything goes smooth.
Now if user try to log in again, then Laravel automatically redirect it to the url without logging, with appended code like this ?code=AQBCM-KbFqB-VJepSJ-45nFURnsvPPdpdqOu...
So how can I logout the user completely and how can I store the details for the next logging??
This is what I am using but it is not working:
public function getSocialAuth($provider=null)
{
if(!config("services.$provider")) abort('404'); //just to handle providers that doesn't exist
return $this->socialite->with($provider)->redirect();
}
public function getSocialAuthCallback($provider=null)
{
if($user = $this->socialite->with($provider)->user()){
dd($user);
/* This is also not working:
$user1 = new User;
$user1->facebook_id = $user->getId();
$user1->email=$user->email();
$user1->fullname=$user->name();
$user1->provider="facebook";
$user1->save();*/
// not working:
User::create([
'facebook_id' => $user->getId(), 'email' => $user->email(),
'fullname' => $user->name()
]);
}else{
return 'something went wrong';
}
}
I want to create a simple check if a user exists in my database just after he is logged on (LDAP Authentication). If he doesn't exist, a record should be created in the db.
Is there any standard CakePHP 3.x -way of doing such things?
Or I can just create a function in my "users" Controller which checks if a user exists in the db and call it in the end of login() function (if user session has been successfully created)?
public function login(){
if ($this->request->is('post')){
$user = $this->Auth->identify();
if ($user) {
$this->Auth->setUser($user);
$this->createStudent($user);
return $this->redirect($this->Auth->redirectUrl());
}
// user is not identified
$this->Flash->error('Your username or password is not correct');
}
}
public function createStudent($user){
$studExists = $this->Students->find('isExists', ['uid' => $user['uid']]);
if (!$studExists) {
$student = $this->Students->newEntity();
$data = ['id' => $user['uid']];
$student = $this->Students->patchEntity($student, $data);
if ($this->Students->save($student)) {
$this->Flash->success(__('It is your first logon. You have been added to our database!'));
return $this->redirect(['action' => 'index']);
} else {
$this->Flash->error(__('You could not be saved in our database. Please, try again.'));
}
}
}
Thank you in advance.
What you have shown works but a better way would using an event from your LDAP authenticate class to notify that a new user record needs to be created in your app. Your table's createStudent() can be set as a listener callback for that event. Also your LDAP authenticate class should also only return info if a matching record is found in your datbase table, which I don't think is the case currently.
You can refer to this HybridAuthAuthenticate which does similar. The readme of the plugin shows how to setup listener for the event.