I have implemented a remember me login in my laravel 5.3 project, but iam running with some issues, when the user return to the page its automaticaly logged in but the custom sessions variables are not set because the session already expired.
I have my sessions lifetime to 120 and expire on close is true.
My question is: how do I check if the user is being authed via remember me token to reasign session variables? I was thinking to create a Middleware for that but i don't know if thats the correct approach.
My customs sessions variables are:
session()->get('client_id') -> int
session()->get('acl') -> array
Can anyone guide me to the right direction?
Check the following solution and see if it works.
Determine if the User Was Authenticated Via the Remember Cookie
Edited:
Add a event Listener to EventServiceProvider
protected $listen = [
'Illuminate\Auth\Events\Login' => [
'App\Listeners\UpdateLoginType#handle',
],
];
Generate event and handler for the listener
php artisan event:generate
Go To UpdateLoginType and edit handle method to check login type
public function handle(Login $event)
{
if (\Auth::viaRemember()) {
//do something
} else {
//do something else
}
}
Make sure your pass the remember variable properly while logging in.
Question similar to this one
Related
I'm trying to log the IP address and login timestamps when users log into our system, and in order to do so I have overriden the authenticated() method of the LoginController :
function authenticated(Request $request, $user) {
$user->update([
'last_login_at' => Carbon::now(),
'last_ip' => $request->getClientIp()
]);
}
The strange thing is that I can see in the database that the last login from some users are several days ago, whether I know for a fact that they performed actions on the website today (while being logged-in), as shown by other logs..
Is there a possibility that authenticated() is not being fired, depending on how the user logs in?
authenticated() method fires always when user logs in.
Possible Problems:
You have not added last_login_at and last_ip in a fillable property in your User Model
Users Has checked remember button. In this case authenticated() method does not fires
It seems okay only thing you missed maybe the return statement? In my application I have similar functionality and working fine try below -
protected function authenticated(Request $request, $user) {
$user->last_login_at = Carbon::now();
$user->last_ip = $request->getClientIp();
$user->save();
return redirect()->intended($this->redirectPath());
}
Not sure how your system is set-up but you can always try listening for the Login event which is fired whenever a user logs in via any means. This includes getting authenticated after the session is expired and the user is automatically logged in via the "remember me" cookie.
In your EventServiceProvider you can add:
\Event::listen(\Illuminate\Auth\Events\Login::class, function ($event) {
$event->user->update([
'last_login_at' => Carbon::now(),
'last_ip' => request()->getClientIp()
]);
});
Note if your session does not actually expire or lasts a very long time users might stay logged in for a very long time.
If you are using Socialite to allow social logins via Facebook, Google, etc. then those will not fire the authenticated event. As another user noted, it also will not fire when the user has checked the remember button.
I'm working on a laravel 5.1 application and I want to check if a user session has expired after each request, in order to redirect the user to the login page.
in order to do so I have created a middleware that runs on every request, the handle function looks like this
public function handle($request, Closure $next)
{
if(session_status() === PHP_SESSION_NONE)
{
return redirect()->guest('login');
}
return $next($request);
}
this does not seem to work correctly, because when I type 'localhost:8000' in google chrome it says 'localhost redirected you too many times', I guess it is because the session have not been started since the user is not logged in, so... is there any better way to do this checking?
You can disable middleware in certain routes. by adding the login route to the excepted_urls array. For example, add the following at the beginning of the class:
protected $except_urls = [
'login'
];
or you can disable it in your web.php/routes.php depending of the version of Laravel you're using by employing route grouping
I am developing a project using laravel 5.2. I use default authentication in this project by running this command.
php artisan make:auth
Everything is working great. Now I want to put some data in session after authenticate the user. I can not find the place where I put my code to store data in session after authenticate the user. I googled but not found any solution.
Finally I got answer from another question. Here i post the solution for who are looking this type of solution
https://stackoverflow.com/a/36491235/2738927
You can check whether the user is logged in or not using the following code.
if (Auth::check()) {
// The user is logged in...
}
Then you can use the session helper class to set the required value in session.
session()->set('session_key', 'session_value');
Additionally, you can remove the session using the forget method.
session()->forget('session_key');
Resources to read.
https://laravel.com/docs/5.3/authentication
https://laravel.com/docs/5.3/session
https://laravel.com/docs/5.3/helpers#method-session
In 5.2 you need to override login() method from Illuminate\Foundation\Auth\AuthenticatesUsers trait in AuthController.php.
To set data use session() helper in login() method:
session(['key' => 'value']);
Building an app in Laravel 5.3, one of the functionalities is for the admin to be able to log into the app as a user, to be able to see what that specific user can see, while maintaining his admin session to be able to go back to the user list and be possible to log in as another user without having to re-authenticate.
Currently implemented the basic out-of-the-box Laravel Auth, meaning if I start another auth session it will terminate my admin session making me having to re-login.
I have checked Laravel Multi Auth but seems to work with two tables (user,admin), which in my case we use one user table and use an ACL for managing roles and deciding whos admin and whos user.
What programming logic ideas do you guys have for this solution? Trying to find other opinions/ideas in how this could be implemented in Laravel 5.x
I've implemented the feature on a project recently. I did this using the session and a middleware. This is how I did it:
Create a controller 'ImpersonateController' and Set two routes for impersonateIn and impersonateOut for the purpose.
Route::get('impersonateIn/{user}', 'ImpersonateController#impersonateIn');
Route::get('impersonateOut', 'ImpersonateController#impersonateOut');
In the ImpersonateController#impersonateIn method just set the user id you want to log in and the URL backUrl into the session variable.
public function impersonateIn($id)
{
session(['impersonated' => $id, 'backUrl' => \URL::previous()]);
return redirect()->to('dashboard');
}
public function impersonateOut()
{
$back_url = Request::session()->get('backUrl');
Request::session()->forget('impersonated', 'secretUrl');
return $back_url ?
redirect()->to($back_url) :
redirect()->to('dashboard');
}
The first part is done. Now every request need to check the if the session has the
impersonated variable set. A good place to do that is a middleware.
Create a middleware to check the session on the handle method. If the impersonated found then log as the user using the Auth::onceUsingId() for the current request only.
class ImpersonateMiddleware
{
public function handle($request, Closure $next)
{
if(Request::session()->has('impersonated'))
{
Auth::onceUsingId(Request::session()->get('impersonated'));
}
}
}
Now you just need to apply the middleware for every request. The best place to do this from the Http/Kernel.php
protected $middlewareGroups = [
'web' => [
//....
\App\Http\Middleware\ImpersonateMiddleware::class,
],
];
The only remaining thing is you need to check the session and replace the logout route to the impersonateOut. Now when the admin logged out from the user will be redirected to the old route.
That's it!
Are you sure you really have to login?
I would stay logged in as admin and simulate user login.
You can allow admin access to all the databases.
In your controller you can use User::find($user_id) instead of Auth::user() for accessing user's data.
https://laravel.com/docs/5.3/database
https://laravel.com/docs/5.3/eloquent
Personaly, I would do this with sessions. I have not used Laravel but I use PHP often, so my answer will be in PHP.
In the header page, you most likely have some kind of session check to see if the user is logged in. For example:
<? php
session_start();
if (isset($_SESSION['user'])){
//do stuff with the user session
} else {
die('User not logged in!');
}
?>
I would change this to something like:
<? php
session_start();
if (isset($_SESSION['fakeuser'])){
//do stuff with the user session
//change logout button to destroy this session instead of logging the user out
}
elseif (isset($_SESSION['user'])){
//do stuff with the user session
} else {
die('User not logged in!');
}
?>
In the page in which you swap users, you would just simply copy the way a session starts when a user logs in. To switch users, you destroy the new 'fakeuser' and you are back to your old session + admin permissions without having to log back in again.
That's the logical approach I would take anyways.
In my laravel 5 application there is a function to allow users with the admin role to reset passwords of anyone not an admin, however this does not force the person to logout and login again. How can I force the user to log out once their password has been changed? I have not made any changes to the middleware for authenticating users or anything.
I don't know if it will work but you can try:
// get current user
$user = Auth::user();
// logout user
$userToLogout = User::find(5);
Auth::setUser($userToLogout);
Auth::logout();
// set again current user
Auth::setUser($user);
I think that the fastest solution is to add a flag to the users DB table, for example a boolean column to_logout and the in the Auth middleware add something like this code.
$user = Auth::user();
if($user->to_logout){
Auth::logout();
$user->update(['to_update' => 0]);
return redirect('/');
}
Trying to avoid additional complexity like adding fields to db, after little bit of investigation I came across next solution.
Idea is based around Laravel 5.4, but should be compatible with all 5.x releases.
The problem lies in way Laravel handles logout. As we can see in https://github.com/laravel/framework/blob/5.4/src/Illuminate/Foundation/Auth/AuthenticatesUsers.php#L154
public function logout(Request $request)
{
$this->guard()->logout();
$request->session()->invalidate();
return redirect('/');
}
The line $request->session()->invalidate(); is flushing request session data and regenerate the ID. So after this one, if we had multiple guards enabled, they all will be logged out.
The idea is to remove just one, session key which corresponds to the current user we are logging out. If we inspect our session (pay attention to "login_*" keys), while users from different guards are logged in, we'll get something like this:
array:5 [▼
"_token" => "qB4zDqDbknpO7FOrfNQ3YuFxpnji95uamJflxSkV"
"_previous" => array:1 [▶]
"_flash" => array:2 [▶]
"login_admin_51ba36addc2b2f9401580f014c7f58ea4e30989d" => 74
"login_user_51ba36addc2b2f9401580f014c7f58ea4e30989d" => 23
]
Instead of flushing whole session, we just need to delete this single, corresponding key. To get current guard session name (session key in example above), we can use guard method:
https://github.com/laravel/framework/blob/5.4/src/Illuminate/Auth/SessionGuard.php#L622
Now we have everything we need to perform this task. Here is the example from the project I'm currently on:
namespace App\Http\Controllers\Admin\Auth;
use Auth;
use App\Http\Controllers\Controller;
use Illuminate\Http\Request;
use Illuminate\Foundation\Auth\AuthenticatesUsers;
class LoginController extends Controller
{
use AuthenticatesUsers;
public function __construct()
{
$this->middleware('guest:admin', ['except' => 'logout']);
}
protected function guard()
{
return Auth::guard('admin');
}
public function logout()
{
// Get the session key for this user
$sessionKey = $this->guard()->getName();
// Logout current user by guard
$this->guard()->logout();
// Delete single session key (just for this user)
$request->session()->forget($sessionKey);
// After logout, redirect to login screen again
return redirect()->route('admin.login');
}
// ... Other code ...
}
With LoginController::logout method we're overriding trait logout (default Laravel logout logic) with our custom, almost the same, but which will allow us to logout single user.
The same logic applies for all our login controllers depending on how much different guards we have.
I just finished this solution and after quick testing it seems to be working fine, but please inspect it carefully before implementing.
If you use Laravel 5.2, you can change session storage engine to Database. In this case every session record will also contain user's ID.
All you need is just to remove respective row from database.
Looking over the docs, it does not appear there is any built-in function for this and a similar request has been proposed which also describes the problem of tracking a single user who has multiple sessions open on more than one device.
I believe you will need to create a custom solution, for example (as #Dinar mentioned) if you are storing user sessions in a database then you could retrieve and destroy a specific user's session when a certain condition is met - changing their password.
$findUser = User::find($userId);
\Session::getHandler()->destroy($findUser->session_id);
Laravel 5.5