Custom login and logout response in Laravel 7.x - api

I am trying to login and logout from a create-react-app application which uses an application with Laravel 7.x as backend. Where can I put the custom response message for /login and /logout auth routes in Laravel 7.x. I used the artisan command for auth scaffolding.
I know about Single Page Application authentication in Laravel. It is given in the Laravel Sanctum page. https://laravel.com/docs/7.x/sanctum. I have followed everything there and have no problems with that.
I get redirected to /home route even when I have commented out the line in LoginController.php
protected $redirectTo = RouteServiceProvider::HOME;
I tried to look up the documentation https://laravel.com/docs/7.x/authentication it says "Laravel provides an empty authenticated(Request $request, $user) method that may be overwritten if desired:". But don't know where this method can be written.

So I will answer my own question. This method is present in the trait AuthenticatesUsers.php which is present in vendor/laravel/ui/auth-backend/ directory.
I added this in the empty method called authenticated() in AuthenticateUsers.php trait present in above link.
/**
* The user has been authenticated.
*
* #param \Illuminate\Http\Request $request
* #param mixed $user
* #return mixed
*/
protected function authenticated(Request $request, $user)
{
return new Response(['success' => 'you have been authenticated'], 200);
}
For custom logout response, use the loggedOut() method in AuthenticatesUsers.php trait.
Hope this helps someone. I also created a pull request in the docs repository, hope it gets accepted. Thanks.

Related

Laravel 8 Jetstream: unable to login with the account seeded using factories and seeder

I am working on a Laravel 8 project. I have noticed that a couple of things have changed including authentication. I am using Jetstream for authentication.
I have installed the Jetstream and I can register and login going to the route /register and /login on the browser. What I am doing now is that for local development, I am creating seeder class so that I can seed the users and log in using those seeded users for local development. But when I log in using those account, it is always complaining that "These credentials do not match our records.".
This is what I have done. I have registered an account on browser using password, "Testing1234". The password hash is saved in the users table. I copied the password and use it in the UserFactory class as follow.
<?php
namespace Database\Factories;
use App\Models\Role;
use App\Models\User;
use Illuminate\Database\Eloquent\Factories\Factory;
use Illuminate\Foundation\Testing\WithFaker;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Str;
class UserFactory extends Factory
{
use WithFaker;
/**
* The name of the factory's corresponding model.
*
* #var string
*/
protected $model = User::class;
/**
* Define the model's default state.
*
* #return array
*/
public function definition()
{
return [
'name' => $this->faker->name,
'email' => $this->faker->unique()->safeEmail,
'email_verified_at' => now(),
'password' => '$2y$10$tive4vPDzIq02SVERWxkYOAeXeaToAv57KQeF1kXXU7nogh60fYO2', //Testing.1234
'remember_token' => Str::random(10),
];
}
}
Then I created a user using factory as follow.
User::factory()->create(['email' => 'testing#gmail.com']);
Then I tried to log in using the user I just created. But it is always complaining, "These credentials do not match our records.". I cannot use the other passwords too. Even the default password that comes with the default user factory class. What is wrong with my code and how can I fix it?
Try using
User::factory()->make([
'email' => 'testing#gmail.com',
]);
I have finally found the issue.
In the JetstreamServiceProvider class, I have added the following code to customise the login flow.
Fortify::authenticateUsing(function (Request $request) {
});
My bad. That is what makes it failing.

Authenticated method in Laravel 6

I'm using Laravel 6. I want to generate a new API token for the user each time the user logged in.
Referring to some answers on StackOverflow, there is a method authenticated in LoginController which is been called just after the user is logged in successfully. I cannot find the authenticated method in Laravel 6.
Is there a new way to achieve the same thing in Laravel 6?
As per Laravel Documentation:
If you need more robust customization of the response returned when a
user is authenticated, Laravel provides an empty authenticated(Request
$request, $user) method that may be overwritten if desired:
/**
* The user has been authenticated.
*
* #param \Illuminate\Http\Request $request
* #param mixed $user
* #return mixed
*/
protected function authenticated(Request $request, $user)
{
return response([
//
]);
}
Just place the following method inside app\Http\Controllers\LoginController (overriding it):
use Illuminate\Http\Request;
protected function authenticated(Request $request, $user)
{
// stuff to do after user logs in
return redirect()->intended($this->redirectPath());
}
Reference:
Laravel -> Authentication -> Authenticating

How to prevent user login automatically after registration in Laravel 5.5

Im using laravel 5.5 and the auth module that provides login and registration modules automatically.
But when i register a new user, it automatically logs in the user and shows the home page.
I dont want to login the user. How do i prevent this ?
You need to overwrite the register() function in /app/Http/Controllers/Auth/RegisterController.php file
This is the original function:
public function register(Request $request)
{
$this->validator($request->all())->validate();
event(new Registered($user = $this->create($request->all())));
$this->guard()->login($user); // this line logs in the user
return $this->registered($request, $user)
?: redirect($this->redirectPath());
}
and you need to copy this function into RegisterController.php and customize it however you want.

Laravel 5.5 - After upgrading auth is not redirecting properly

I just upgraded my application from Laravel 5.4 to v 5.5. Non authenticated users are not redirecting properly now.
Normally a non authenticated user should be redirected to /manage/login but it is redirected to /login route.
Everything was working perfect in Laravel v 5.4
My app contain two guards.
Routing in web.php
Auth::routes();
Route::middleware(['auth:manager'])->group(function () {
Route::get('/manage', 'Manage\AdminController#dashboard')->name('manage.home');
});
So before upgrade a non authenticated user trying to access /manage was redirected to /manage/login but after upgrading it is redirecting to /login.
I have Auth Controllers copied and modified as needed in Manage\Auth.
Similarly Views are in folder structure Manage\Auth.
My LoginController in Controllers\Manage\Auth
|
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 = '/manage/';
/**
* Create a new controller instance.
*
* #return void
*/
public function __construct()
{
$this->middleware('guest')->except('logout');
}
public function showLoginForm()
{
return view('manage.auth.login');
}
public function logout(Request $request)
{
$this->guard()->logout();
$request->session()->flush();
$request->session()->regenerate();
return redirect('/manage');
}
protected function guard()
{
return Auth::guard('manager');
}
I faced the same problem, and it's quit simple to solve.
the point is that if you are using guards you were probably handling unauthenticated exception in your app/Exceptions/Handler.php . when using laravel 5.4 .
After update to 5.5 this is done under vendor/laravel/framework/src/Illuminate/Foundation/Exceptions/Handler.php .
You should refer to this Laravel 5.5 change unauthenticated login redirect url for more details about how to solve it.

How do i use Behat with Mink and WebApiContext?

The project i'm working on has a api behind a login.
I'm using behat with mink to login:
Scenario: Login
Given I am on "/login/"
And I should see "Login"
When I fill in "_username" with "test"
And I fill in "_password" with "test"
And I press "_submit"
Then I should be on "/"
This works..
However, the login session is not stored whenever i want to do the following using the WebApiContext:
Scenario: Getting the list of pages
When I send a GET request to "/api/pages.json"
Then print response
I'm using both scenarios in the same feature. My FeatureContext class looks something like this:
class FeatureContext extends MinkContext
{
public function __construct(array $parameters)
{
$context = new WebApiContext($parameters['base_url']);
$context->getBrowser()->getClient()->setCookieJar(new \Buzz\Util\CookieJar());
$this->useContext('web', $context);
}
}
I added the cookiejar idea from this issue without success.. When i print the response i just see the HTML page from the login screen..
Does anyone have any idea if i'm going at this totally the wrong way or am i somewhat in the right direction?
I am successfully using the same method. I don't think there's a standard way of doing this. As far as you understand the cookie basics you should be able to implement the solution.
In a common scenario, a client sends an authentication request to the server with some credentials, the servers validates it, starts an authenticated session and sends back a cookie with that session id. All following requests contain that id, so the server can recognise the callee. A specific header can be used instead of the cookie, or a database can be used instead of the session, but the principle is the same and you can (relatively) easily simulate it with Mink.
/**
* Start a test session, set the authenticated user and set the client's cookie.
*
* #Given /^I am signed in$/
*/
signIn()
{
session_start();
$_SESSION['user'] = 'jos';
$this->getSession()->getDriver()->setCookie(session_name(), session_id());
session_commit();
}
The above step definition (Behat 3) is the basics of it, you manually create the authenticated session and set to the client it's id. That must be also what the other example illustrates.
PHP's sessions can be problematic when you start doing more complex things and there are a couple of big underwater rocks with this solution. If you want to run assertions from both perspectives (the client and the server) you might often need to have your sessions synced. This can be done by updating the cookie before all Mink steps and reloading the session after.
/**
* #beforeStep
* #param BeforeStepScope $scope
*/
public function synchroniseClientSession(BeforeStepScope $scope)
{
// Setup session id and Xdebug cookies to synchronise / enable both.
$driver = $this->getSession()->getDriver();
// Cookie must be set for a particular domain.
if ($driver instanceof Selenium2Driver && $driver->getCurrentUrl() === 'data:,') {
$driver->visit($this->getMinkParameter('base_url'));
}
// Also enables the debugging support.
$driver->setCookie(session_name(), session_id());
$driver->setCookie('XDEBUG_SESSION', 'PHPSTORM');
}
/**
* #afterStep
* #param AfterStepScope $scope
*/
public function synchroniseServerSession(AfterStepScope $scope)
{
$driver = $this->getSession()->getDriver();
// Only browser kit driver, only initiated requests, only not repeating requests.
if (!$driver instanceof BrowserKitDriver) {
return;
} elseif (($request = $driver->getClient()->getRequest()) === null) {
return;
} elseif ($request === self::$request) {
return;
}
// Your logic for reloading the session.
self::$request = $request;
}
The biggest problem I had was the session reloading. This might be due to my framework of choice, which I doubt. The very first code snippet has session_commit(), which saves and closes the session. In theory in the following step definitions you must be able to session_id(/* session id from the cookie… */); and session_start();, but in practice that didn't work and no session data was actually loaded from the file, though the session did start. To solve this I created a custom session manager with reload() method using session save handler.
Second problem is where you cannot simply close the session without either writing it or destroying it (the support is added in PHP 5.6) on which relies the reloading itself. I reinvented the wheel with a flag for the session manager which tells it whether to write or just to close it.
:)