Laravel : transforming a request into another - laravel

I want to log my users as soon as they register. here's my UserController's code (which works) :
<?php
namespace App\Http\Controllers;
use App\Http\Requests\Login;
use App\Http\Requests\Register;
use App\User;
class UserController extends Controller
{
public function register(Register $request)
{
User::create($request->all());
$loginRequest = new Login();
$loginRequest['email'] = $request->get('email');
$loginRequest['password'] = $request->get('password');
return $this->login($loginRequest);
}
public function login(Login $request)
{
return 'ok';
}
}
I feel I'm doing something ugly with my $loginRequest. Is there a neater way to do the same ? Aka transform my Register request into a Login request ?

You are simply trying to logged in user into his account after the registration so use Auth::login($user)
class UserController extends Controller
{
public function register(Register $request)
{
$user = User::create($request->all());
\Auth::login($user);
}
}

As soon as user register you can use this snippet of code to attempt a login
if (Auth::attempt(['email' => request('email'), 'password' => request('password')])) {
return Redirect::route('dashboard');
}
So the code should be
User::create($request->all());
$loginRequest = new Login();
$loginRequest['email'] = $request->get('email');
$loginRequest['password'] = $request->get('password');
if (Auth::attempt(['email' => $request->get('email'),
'password' => $request->get('password')])) {
return Redirect::route('dashboard');
}

Related

Temporary identifier passed back by server does not match laravel socialite

I am facing an issue when trying to login and register a user using Twitter. Google is working except for Twitter. I cant seem to figure it out.
Temporary identifier passed back by server does not match that of stored temporary credentials. Potential man-in-the-middle.
<?php
namespace App\Http\Controllers;
use Exception;
use App\Models\User;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Laravel\Socialite\Facades\Socialite;
class TwitterController extends Controller
{
protected $redirectTo = '/home';
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($this->redirectTo);
}
public function findOrCreateUser($user, $provider)
{
$authUser = User::where('provider_id', $user->id)->first();
if ($authUser) {
return $authUser;
}
return User::create([
'name' => $user->getName(),
'username' => $user->getName(),
'email' => $user->getEmail(),
'provider' => $provider,
'provider_id' => $user->getId()
]);
}
}

Laravel session is lost or not created on redirect

We are trying to setup the Facebook social connect on our Laravel application, but it seems like we have an issue on session creation.
Here is the code for the Controller :
<?php
namespace App\Http\Controllers\Auth;
use App\Http\Controllers\Controller;
use Laravel\Socialite\Facades\Socialite;
use App\Services\SocialAuthService;
class SocialAuthController extends Controller
{
public function redirect()
{
return Socialite::driver('facebook')->redirect();
}
public function callback(SocialAuthService $service)
{
$user = $service->createOrGetUser(Socialite::driver('facebook')->stateless()->user());
auth()->login($user);
return redirect()->intended('/');
}
}
And the code for the service :
<?php
namespace App\Services;
use Laravel\Socialite\Contracts\User as ProviderUser;
use Myproject\Users\User;
use Myproject\Users\SocialLogin;
class SocialAuthService
{
public function createOrGetUser(ProviderUser $providerUser)
{
$account = SocialLogin::where('provider', '=', 'facebook')
->where('provider_user_id', '=', $providerUser->getId())
->first();
if ($account) {
return $account->user;
}
$user = User::where('email', '=', $providerUser->email)->first();
if (!$user) {
$fullname = explode(' ', $providerUser->getName());
$user = User::create([
'email' => $providerUser->getEmail(),
'firstname' => $fullname[0],
'lastname' => $fullname[1],
'password' => md5(rand(1, 9999)),
]);
}
$account = new SocialLogin([
'provider_user_id' => $providerUser->getId(),
'provider' => 'facebook'
]);
$account->user()->associate($user);
$account->save();
return $user;
}
}
And finally the Model :
<?php
namespace Myproject\Users;
use Illuminate\Database\Eloquent\Model;
use Myproject\Users\User;
class SocialLogin extends Model
{
protected $table = 'social_logins';
protected $fillable = ['user_id', 'provider_user_id', 'provider'];
public function user()
{
return $this->belongsTo(User::class);
}
}
When we're trying to connect via Facebook, the information is correctly insert in Database, and the callback URL set on Facebook Developers correspond to what we have in our .env, so the redirection is correctly done but at the end we don't have any session created for the user.
I think the issue comes from cross-domain, here are the interesting parts of our .env file :
APP_URL=https://www.website.com
APP_DOMAIN=website.com
SESSION_DOMAIN=.website.com
CACHE_DRIVER=redis
SESSION_DRIVER=redis
SESSION_LIFETIME=120
FACEBOOK_REDIRECT=https://www.website.com/callback/facebook
GOOGLE_REDIRECT=https://www.website.com/auth/google/callback
And our routing on web.php :
Route::domain('{subdomain}.{domain}')->middleware('locale')->group(function () {
Route::get('/callback/facebook', 'Auth\SocialAuthController#callback');
Route::get('/redirect/facebook', 'Auth\SocialAuthController#redirect');
});
I really think the issue is located on routing or SESSION_DOMAIN, but we tried to :
delete the session domain
routing outside the middleware locale, in a middleware auth
It still doesn't affect the login.

How to send data colected with Laravel Livewire to Fortify?

I'm not familiar with Vue.js at all, so found a good replacement using Livewire.
The challenge that I've got to solve is to have a user friendly registration on my website using Fortify + Livewire. The registration process is a multistep one and depends on the choices that the user makes it will load the relative fields.
So far I set up the Fortify views by adding in the FortifyServiceProvider.php file the following code:
Fortify::loginView(function () {
return view('auth.login');
});
Fortify::registerView(function () {
return view('auth.register');
});
The auth/login.blade.php view loading the livewire component which is basically a form:
<form action="{{ route('register') }}" method="POST" wire:submit.prevent="submit">
/**
* Here would go the inputs that must be shown depends on what users choice
* (is it an ordinar user or a company)
*/
<button type="submit">Save<button/>
</form>
The multiform challenge would be resolved by adding $step property into the Register.php class:
class RegisterForm extends Component
{
public $step;
public function mount()
{
$this->step = 0;
}
public function submit()
{
if ($this->step < 3) {
$this->step++;
} else {
// pass all the data to the fortify register method
// <-- Here is my trouble!
}
}
}
which will be incremented by passing each of the registration steps ($this->step++).
The most important thing that is quite complicated for me is how to prevent form submission to have the validation + form changes and by the end all the set of the data to pass trough Fortify registration process?
Look at the fortify Controller for register
public function store(Request $request, CreatesNewUsers $creator): RegisterResponse
{
event(new Registered($user = $creator->create($request->all())));
$this->guard->login($user);
return app(RegisterResponse::class);
}
T
use Illuminate\Auth\Events\Registered;
use Illuminate\Support\Facades\Auth;
use Laravel\Fortify\Contracts\CreatesNewUsers;
use Livewire\Component;
class Register extends Component
{
public $name;
public $email;
public $password;
public $password_confirmation;
public function submit(CreatesNewUsers $creator)
{
event(new Registered($user = $creator->create([
'name' => $this->name,
'email' => $this->email,
'password' => $this->password,
'password_confirmation' => $this->password_confirmation,
])));
Auth::guard()->login($user);
$this->redirect('home');
}
public function render()
{
return view('livewire.register');
}
}
Something like this will work for your use case.
You are still using the fortify Action and Still Firing the Event
The response is to use app container
<?php
use Illuminate\Auth\Events\Registered;
use Illuminate\Support\Facades\Auth;
use App\Actions\Fortify\CreateNewUser;
use Livewire\Component;
class Register extends Component
{
public $name;
public $email;
public $password;
public $password_confirmation;
public function submit()
{
event(new Registered($user = app(CreateNewUser::class)->create([
'name' => $this->name,
'email' => $this->email,
'password' => $this->password,
'password_confirmation' => $this->password_confirmation,
])));
Auth::guard()->login($user);
$this->redirect('home');
}
public function render()
{
return view('livewire.register');
}
}
The response is to use dependency injection by injecting the Fortify CreateNewUser action in the mounting method of the Livewire component.
use Illuminate\Auth\Events\Registered;
use Illuminate\Support\Facades\Auth;
use App\Actions\Fortify\CreateNewUser;
use Livewire\Component;
class Register extends Component
{
public $name;
public $email;
public $password;
public $password_confirmation;
protected $creator;
public function mount(CreateNewUser $creator)
{
$this->creator = $creator;
}
public function submit()
{
event(new Registered($user = $this->creator->create([
'name' => $this->name,
'email' => $this->email,
'password' => $this->password,
'password_confirmation' => $this->password_confirmation,
])));
Auth::guard()->login($user);
$this->redirect('home');
}
public function render()
{
return view('livewire.register');
}
}
you can use blade example
#if($step > 3)
<input name="name" type="text">
#endif

Laravel redirect in controller from another class

I try co redirect to other route in controller, unfortunately dont work.
My idea is redirect to 'home' when conditions in method canStart from my service class are realize.
My controller
public function start($id) {
$user = auth()->user();
$this->testService->canStart($id);
//do something ...
return view('common/start/',
[
'id' => $id,
'data' => $data,
'logs' => $logs
]);
}
Other Class method
public function canStart($id) {
return redirect()->route('home');
}
public function canStart($id) {
return redirect()->route('home')->send();
}
It work now

Laravel passport throwing error: 'Call to a member function createToken() on null'

So i'm trying to create an auth repository test using phpunit but i keep getting the error 'Call to a member function createToken() on null'. I think this is due to the RefreshDatabase trait but i'm installing passport on setup so i'm a bit lost. Any help is appreciated!
AuthRepository test
namespace Tests\Repository;
use App\Contracts\Auth;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;
class AuthRepositoryTest extends TestCase
{
use RefreshDatabase;
protected $authRepository;
protected function setUp(): void
{
parent::setUp();
$this->artisan('passport:install');
$this->authRepository = app()->make(Auth::class);
}
/**
* Test Successful Login
*
* #return void
*/
public function testSuccessfulLogin(): void
{
$request = new \Illuminate\Http\Request();
$request->setMethod('POST');
$request->replace(['name' => 'test', 'email' => 'test', 'password' => 'testing']);
$this->authRepository->register($request);
$request = new \Illuminate\Http\Request();
$request->setMethod('POST');
$request->replace(['email' => 'test', 'password' => 'testing']);
$this->authRepository->login($request);
}
}
Test Case
<?php
namespace Tests;
use Illuminate\Foundation\Testing\TestCase as BaseTestCase;
abstract class TestCase extends BaseTestCase
{
use CreatesApplication;
protected function setUp(): void
{
parent::setup();
}
}
AuthRepository
<?php
namespace App\Repositories;
use App\Contracts\Auth;
use Illuminate\Support\Facades\Auth as Authenticate;
use App\User;
class AuthRepository implements Auth
{
public function Register($request)
{
$user = new User([
'name' => $request->input('name'),
'email' => $request->input('email'),
'password' => bcrypt($request->input('password'))
]);
$user->save();
return $user;
}
public function Login($request)
{
$credentials = $request->all();
if (!Authenticate::attempt($credentials))
return response()->json([
'message' => 'Unauthorized'
], 401);
$user = $request->user();
$tokenResult = $user->createToken('Personal Access Token');
$token = $tokenResult->token;
$token->save();
return $tokenResult;
}
}
This is happened because the controller is trying to get the user data and create a token based on that.
In your case (happened to me too), there was a user variable which pointing the request to get the user credential while the user data is unknown because the user is not yet logged in.
To be clear, please take a look at your code within this line:
$user = $request->user();
$tokenResult = $user->createToken('Personal Access Token');
$token = $tokenResult->token;
To fix that, change the line of $user = $request->user() to this:
$user = User::whereEmail($request->email)->first();
$tokenResult = $user->createToken('Personal Access Token');
$token = $tokenResult->token;

Resources