I am implementing this shipping cart for laravel (https://github.com/darryldecode/laravelshoppingcart/issues/250). When a user logs in I would like to continue their cart, for this to happen I would need to save the session id then merge that data on login.
The problem I am having is that when i flash the cart inside \app\Http\Controllers\Auth\LoginController.php, the session id changes. It seems that all files inside Auth changes when getId().
session()->flash('guest_cart', [
'session' => session()->getId(),
'data' => cart()->getContent()
]);
So if I flash the session else where, how do I merge it into the new user cart on login if I am not able to retrieve the the original getId()?
When I output dd(session()->all()); inside LoginController it shows an empty array. I would somehow need to capture session('guest_cart.data'); during login.
I tried adding this to LoginController.php
protected function authenticated(Request $request, $user){
if(Auth::check()){
$session_id = \Session::getId();
$cartObj = \Cart::session($session_id)->getContent();
if (\Auth::guest()) {
session()->flash('guest_cart', [
'session' => $session_id,
'data' => $cartObj
]);
}
dd(session()->all());
}
but again guest_cart returns an empty array because $session_id = \Session::getId(); has changed.
where would I create an event to retrieve during login? Can you point me towards a direction on how to accomplish this?
We can just override the authenticated() method in Auth\LoginController.php to save anything to the session. If you want to store only few values then just update it.
authenticated() method is called just after the user is logged in & it is defined empty in the trait AuthenticatesUsers used in LoginController.
use Illuminate\Http\Request;
protected function authenticated(Request $request, $user)
{
if(Auth::check){
//assuming that you have a cart relationship with user.
$cartData = Auth::user()->cart()->getContent();
$request->session()->put('cart_data', $cartData);
}
return redirect()->intended($this->redirectPath());
}
If you have a lot of things to do you can then create an event, then use listeners to listen to that event. We will call the event from authenticated method itself.
In Laravel 5.8 the Auth\LoginController is just:
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 = '/my-team';
/**
* Create a new controller instance.
*
* #return void
*/
public function __construct()
{
$this->middleware('guest')->except('logout');
}
}
On login I want to perform some custom actions for the user, but I can't figure out where I can place this code. The documentation doesn't seem to help.
Is there a method I can overwrite/extend with my own?
Laravel 5.2 used to have a login() method in the Auth controller where I could just write additional code.
You can override the login() method in LoginController. As you said, in Laravel 5.8 the login() method doesn't exist, but you can define it yourself. The newly defined login() method will override the default one and then you can do whatever extra you want to after or before the user signs in. Here is a snippet from Laracasts:
public function login(Request $request)
{
$this->validateLogin($request);
if ($this->hasTooManyLoginAttempts($request)) {
$this->fireLockoutEvent($request);
return $this->sendLockoutResponse($request);
}
if(Auth::attempt(['email' => $request->email, 'password' => $request->password, 'is_activated' => 1])) {
// return redirect()->intended('dashboard');
} else {
$this->incrementLoginAttempts($request);
return response()->json([
'error' => 'This account is not activated.'
], 401);
}
$this->incrementLoginAttempts($request);
return $this->sendFailedLoginResponse($request);
}
Just go through it and see what has been done there. In short, you can modify the login() method to do whatever you want before or after a user signs in.
There are two functions provided by the AuthenticatesUsers trait. You can customize those in the login controller.
Login Form
public function showLoginForm()
{
return view('auth.login');
}
Handle Login
public function login(Request $request)
{
$this->validateLogin($request);
// If the class is using the ThrottlesLogins trait, we can automatically throttle
// the login attempts for this application. We'll key this by the username and
// the IP address of the client making these requests into this application.
if ($this->hasTooManyLoginAttempts($request)) {
$this->fireLockoutEvent($request);
return $this->sendLockoutResponse($request);
}
if ($this->attemptLogin($request)) {
return $this->sendLoginResponse($request);
}
// If the login attempt was unsuccessful we will increment the number of attempts
// to login and redirect the user back to the login form. Of course, when this
// user surpasses their maximum number of attempts they will get locked out.
$this->incrementLoginAttempts($request);
return $this->sendFailedLoginResponse($request);
}
You can place these two functions in the login controller and make changes as you want.
The best place to add your custom actions is to override authenticated method in your LoginController
protected function authenticated(Request $request, $user)
{
// Your code
}
Just go to where the Illuminate\Foundation\Auth\AuthenticatesUsers trait is located and you will find all the methods you want
it's located in :
vendor/laravel/framework/src/Illuminate/Foundation/Auth/AuthenticatesUsers
Or you can overwrite it in the LoginController to do what ever you want
I have searched all over the place, none of the answers was to my needs.
I have a Laravel app, with various pages that require the user to be logged in.
The normal redirect in Laravel after login is to the home page.
How can I make a redirect to the original page that requested the login?
For example:
A user tries to go to example.com/page/1 that is for authenticated users only. He is redirected to the login page, submit the form and then redirects to the home page. How can I redirect him back to example.com/page/1 or whatever page that he came from?
You can use intended method for this purpose, From the docs:
The intended method on the redirector will redirect the user to the
URL they were attempting to access before being intercepted by the
authentication middleware. A fallback URI may be given to this method
in case the intended destination is not available.
In your Login Controller add the below code:
public function authenticate(Request $request)
{
$credentials = $request->only('email', 'password');
if (Auth::attempt($credentials)) {
// Authentication passed...
return redirect()->intended('dashboard');
}
}
You could potentially hook in to Laravel's intended() method. Usually, this would be a guarded route that a user tried to access before they were redirected to the login page but you can manually set it to what ever you want it to be.
In your LoginController add the following:
public function showLoginForm()
{
if (!session()->has('url.intended')) {
redirect()->setIntendedUrl(session()->previousUrl());
}
return view('auth.login');
}
This will check to see if the intended url is set, if it isn't it will set it to the previous url.
in your LoginController :
protected function authenticated(Request $request, $user) {
return redirect()->back();
}
I am preventing users who do not have a role of 'admin' from logging in to the dashboard in a Laravel 5.5 app like this in app/http/Controllers/auth/LoginController.php..
protected function credentials(\Illuminate\Http\Request $request)
{
$credentials = $request->only($this->username(), 'password');
return array_add($credentials, 'type', 'admin');
}
This works well, but if somebody resets their password using the forgotten password function then it bypasses this function and lets them in to the dashboard.
How can I lock the dashboard down to prevent this happening?
Should I disable auto login after password reset, will this be enough?
Use Middleware, you will have full control on all requests in your app.
Also, you might want to have a look at (spatie/laravel-permission) # github it will make your Role/Permission process really easier.
Overwrite the authenticated method in LoginController. Place the code below in the LoginController.
protected function authenticated(Request $request, $user)
{
if ( Use your Logic here ) {
return redirect()->route('admin.home');
}
return redirect('/home');
}
I'm currently using 2 projects. 1 front end (with laravel backend to communicate with API) and another laravel project (the API).
Now I use Laravel Passport to authenticate users and to make sure every API call is an authorized call.
Now when I want to log out my user, I send a post request to my API (with Bearer token) and try to log him out of the API (and clear session, cookies,...)
Then on the client I also refresh my session so the token is no longer known. Now when I go back to the login page, it automatically logs in my user. (Or my user is just still logged in).
Can someone explain me how to properly log out a user with Laravel passport?
Make sure that in User model, you have this imported
use Laravel\Passport\HasApiTokens;
and you're using the trait HasApiTokens in the User model class using
use HasApiTokens
inside the user class.
Now you create the log out route and in the controller,
do this
$user = Auth::user()->token();
$user->revoke();
return 'logged out'; // modify as per your need
This will log the user out from the current device where he requested to log out. If you want to log out from all the devices where he's logged in. Then do this instead
$tokens = $user->tokens->pluck('id');
Token::whereIn('id', $tokens)
->update(['revoked'=> true]);
RefreshToken::whereIn('access_token_id', $tokens)->update(['revoked' => true]);
Make sure to import these two at the top
use Laravel\Passport\RefreshToken;
use Laravel\Passport\Token;
This will revoke all the access and refresh tokens issued to that user. This will log the user out from everywhere. This really comes into help when the user changes his password using reset password or forget password option and you have to log the user out from everywhere.
You need to delete the token from the database table oauth_access_tokens
you can do that by creating a new model like OauthAccessToken
Run the command php artisan make:model OauthAccessToken to create the model.
Then create a relation between the User model and the new created OauthAccessToken Model , in User.php add :
public function AauthAcessToken(){
return $this->hasMany('\App\OauthAccessToken');
}
in UserController.php , create a new function for logout:
public function logoutApi()
{
if (Auth::check()) {
Auth::user()->AauthAcessToken()->delete();
}
}
In api.php router , create new route :
Route::post('logout','UserController#logoutApi');
Now you can logout by calling posting to URL /api/logout
This is sample code i'm used for log out
public function logout(Request $request)
{
$request->user()->token()->revoke();
return response()->json([
'message' => 'Successfully logged out'
]);
}
Create a route for logout:
$router->group(['middleware' => 'auth:api'], function () use ($router) {
Route::get('me/logout', 'UserController#logout');
});
Create a logout function in userController ( or as mentioned in your route)
public function logout() {
$accessToken = Auth::user()->token();
DB::table('oauth_refresh_tokens')
->where('access_token_id', $accessToken->id)
->update([
'revoked' => true
]);
$accessToken->revoke();
return response()->json(null, 204);
}
I am using Laravel 6.12.0, below function is working for me.
public function logout(Request $request){
$accessToken = Auth::user()->token();
$token= $request->user()->tokens->find($accessToken);
$token->revoke();
$response=array();
$response['status']=1;
$response['statuscode']=200;
$response['msg']="Successfully logout";
return response()->json($response)->header('Content-Type', 'application/json');
}
This is my first post.. and i find a clean solution (Laravel last Version)
/**
* Logout api
*
* #return \Illuminate\Http\Response
*/
public function logout(Request $request)
{
if (Auth::check()) {
$token = Auth::user()->token();
$token->revoke();
return $this->sendResponse(null, 'User is logout');
}
else{
return $this->sendError('Unauthorised.', ['error'=>'Unauthorised'] , Response::HTTP_UNAUTHORIZED);
}
}
Below is the simplest way I found to do it.
1. USE database SESSION INSTEAD OF file SESSION
Official documention
php artisan session:table
php artisan migrate
Replace SESSION_DRIVER=file by SESSION_DRIVER=database in your .env file.
2. DELETE USER SESSION RIGHT AFTER LOGIN
After a user is redirected to your frontend and logs in to finally get a token, you probably call a route in api/routes.php to get the user information, that's where I'm closing the user backend session before sending back user information to the frontend:
Route::middleware('auth:api')->get('/user', function (Request $request) {
// Close user session here
Illuminate\Support\Facades\DB::table('sessions')
->whereUserId($request->user()->id)
->delete();
return $request->user();
});
3. REVOKE TOKENS AT LOGOUT
Then, to "log out" (actually, revoke tokens) the user from the frontend, you just need to call another route to revoke the token and refresh_token:
Route::middleware('auth:api')->post('/logout', function (Request $request) {
// Revoke access token
// => Set oauth_access_tokens.revoked to TRUE (t)
$request->user()->token()->revoke();
// Revoke all of the token's refresh tokens
// => Set oauth_refresh_tokens.revoked to TRUE (t)
$refreshTokenRepository = app('Laravel\Passport\RefreshTokenRepository');
$refreshTokenRepository->revokeRefreshTokensByAccessTokenId($request->user()->token()->id);
return;
});
You may prefer to put these two closures in the UserController.
Hope help someone:
if (Auth::check()) {
$request->user()->tokens->each(function ($token, $key) {
$token->delete();
});
}
Good Luck.
I use this in my project to logout from multiple device.
public function logout(Request $request, $devices = FALSE)
{
$this->logoutMultiple(\Auth::user(), $devices);
return response()->json([], 204);
}
private function logoutMultiple(\App\Models\User $user, $devices = FALSE)
{
$accessTokens = $user->tokens();
if ($devices == 'all') {
} else if ($devices == 'other') {
$accessTokens->where('id', '!=', $user->token()->id);
} else {
$accessTokens->where('id', '=', $user->token()->id);
}
$accessTokens = $accessTokens->get();
foreach ($accessTokens as $accessToken) {
$refreshToken = \DB::table('oauth_refresh_tokens')
->where('access_token_id', $accessToken->id)
->update(['revoked' => TRUE]);
$accessToken->revoke();
}
}
Try this code to help you to logout from passport authentication.
Route::post('/logout', function(){
if (Auth::check()) {
Auth::user()->AauthAcessToken()->delete();
}
return response()->json([
'status' => 1,
'message' => 'User Logout',
], 200);
});
check whether your model contains OauthAccessToken which needs to connect with the database oauth_access_tokens. The access token is stored in the database table oauth_access_tokens. and makes a relation from users to oauth_access_tokens.
public function AauthAcessToken(){
return $this->hasMany(OauthAccessToken::class);
}
You can use following code to remove to token for logged in user.
$request->user()->token()->revoke();
If you want to learn about this in-depth then watch this tutorial:
https://www.youtube.com/watch?v=UKSQdg1uPbQ
public function logout(Request $request)
{
$request->user()->token()->revoke();
if ($request->everywhere) {
foreach ($request->user()->tokens()->whereRevoked(0)->get() as $token) {
$token->revoke();
}
}
return response()->json(['message' => 'success']);
}