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
Related
i want to know if there is any way to simulate the login as user and make the session for that user .i want my help-desk to see the site from users vision so they need to log in as user as long as i cant show the user s password to the admin (its not possible as far as i know if its not that would be a good solution too ). i want to place a button with some text for example :
LoginAsThisUser
and when my help desk clicks on the button he logs in as the user is there any way to do that ??
It's possible, and it's fairly simple to do. All you need to do is to create a route, something like this:
Route::get('admin/login-as-user/{id}', 'Admin\UserController#loginAsUser')->name('login.as.user');
After that, pass the route to your LoginAsThisUser button with desired user id :
LoginAsThisUser
And create a function in your controller:
public function loginAsUser($id)
{
$user = User::findOrFail($id);
Auth::login($user);
return redirect('/');
}
Note: this is not tested, let me know if you encounter any errors.
use Illuminate\Support\Facades\Auth;
//use user_id
Auth::loginUsingId(1);
// Login and "remember" the given user...
Auth::loginUsingId(1, true);
$user=User::find($userId);
//use Authenticatable user
Auth::login($user);
// Login and "remember" the given user...
Auth::login($user, true);
also use
Auth::guard('notDeafault')->login($user);
if you want switch default guard
With the Auth facade, you can use the loginUsingId method
Auth::loginUsingId($user_id);
This method allows you to force login without a password. But it does not allow you to retrieve cookies or cache from your user's browser that may impact their viewing.
There is possible to get another users session? Suppose, there is user with admin privilegies and I need that admin have functionality, to access another user's session and remove it. (So that another user will automatically logged out).
Is there some tools in laravel for this? or I need do same things, as I would do for native PHP application ?
Have an admin panel and have the setting to block the user.
Have a column in your database table, say is_blocked with datatype as tinyint, with 1 meaning the user is blocked.
In your application, have an additional check of whether the current logged in user is blocked in a custom made middleware. If yes, log them out, else continue with request target.
Middleware Snippet:
<?php
namespace App\Http\Middleware;
use Closure;
use Auth;
use Session;
class IsBlockedMiddleware{
public function handle($request, Closure $next){
Auth::user()->refresh();
if(Auth::user()->blocked === 1){
Auth::logout();
Session::flash('error','Your account is blocked'); // show the flash message in your blade file
return redirect()->route('login');
}
return $next($request);
}
}
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 have a feeling this is a very dumb question and there's probably something really tiny I just overlooked, but I'm stumped anyway.
Currently, I have an app with a few pages that are protected through middleware. If the user does not meet the requirements of these middleware, they are redirected to a login page. Now after they log in, I want them to be sent back to the page they tried to visit.
I've tried numerous things to accomplish this, but none work. What I'm trying to do now is the following:
User attempts to access an admin page (for example /admin): PagesController#adminDashboard
When they access the overview() method in the controller (same as index(), but for admins), a session variable is set containing the url they tried to visit (/admin)
The user is redirected to the login page and logs in (SessionsController#create and #store)
After logging in, they are redirected to the session variable with the intended URL
This is how I tried to do it:
PagesController
public function adminDashboard()
{
$intended = '/admin';
session('intended-url', $intended);
//dd(session('intended-url');
$schools = School::all();
$articles = Article::all();
$sights = Sight::all();
return view('admin', compact('sights', 'articles', 'schools'));
}
SessionsController
public function store()
{
/*
...
*/
$intendedURL = session('intended-url');
if($intendedURL != null)
{
return redirect($intendedURL);
}
else
{
return redirect()->home();
}
Using dd() a few times here and there, I found out that it doesn't even set the session variable at the very start (commented dd() in PagesController returns null).
I've tried doing this using Session::put(), Session::set(), using square brackets as in session(['intended-url', '/admin']), but none of it gives me the result I'm looking for :(
Does anyone have any advice on how to do this, or perhaps a different way of accomplishing the same goal, but more efficiently? Thank you!
EDIT: I don't think the default Laravel redirect to intended page will work here, since I rewrote most of the login system from scratch to suit some specific needs. Unless anyone knows how that redirect works behind the scenes and I can over-/rewrite it
If you are using the default auth system, you can use this to redirect users to the page they wanted to view:
return redirect()->intended('fallback/uri');
why u are not using middleware just make new middleware
php artisan make:middleware admin
and add this code of public function handle
if (!Auth::guest() && Auth::user()->admin) {
return $next($request);
}
return redirect('/')->with('warning', 'This Area only For Admin');
add this code in kernal on protected $routeMiddleware
protected $routeMiddleware = [
'admin' => \App\Http\Middleware\admin::class,
];
make new column in users table
$table->boolean('admin')->default(false);
now you can use your construct function
public function __construct()
{
$this->middleware('admin');
}
Note:- where u add $this->middleware('admin'); all controller will be locked for users and guest only admin can use this controller
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.