【发布时间】:2016-08-14 22:17:53
【问题描述】:
在我的 laravel 5 应用程序中,有一个功能允许具有管理员角色的用户重置任何非管理员的密码,但这不会强制该人注销并再次登录。更改密码后如何强制用户注销?我没有对用于验证用户或其他任何东西的中间件进行任何更改。
【问题讨论】:
在我的 laravel 5 应用程序中,有一个功能允许具有管理员角色的用户重置任何非管理员的密码,但这不会强制该人注销并再次登录。更改密码后如何强制用户注销?我没有对用于验证用户或其他任何东西的中间件进行任何更改。
【问题讨论】:
$findUser = User::find($userId);
\Session::getHandler()->destroy($findUser->session_id);
Laravel 5.5
【讨论】:
为了避免额外的复杂性,比如向 db 添加字段,经过一点调查后,我遇到了下一个解决方案。
Idea 基于 Laravel 5.4,但应该与所有 5.x 版本兼容。
问题在于 Laravel 处理注销的方式。正如我们在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('/');
}
$request->session()->invalidate(); 行正在刷新请求会话数据并重新生成 ID。所以在这之后,如果我们启用了多个保护,它们都会被注销。
我们的想法是只删除一个会话密钥,它对应于我们正在注销的当前用户。如果我们检查我们的会话(注意“login_*”键),当来自不同守卫的用户登录时,我们会得到这样的结果:
array:5 [▼
"_token" => "qB4zDqDbknpO7FOrfNQ3YuFxpnji95uamJflxSkV"
"_previous" => array:1 [▶]
"_flash" => array:2 [▶]
"login_admin_51ba36addc2b2f9401580f014c7f58ea4e30989d" => 74
"login_user_51ba36addc2b2f9401580f014c7f58ea4e30989d" => 23
]
我们只需要删除这个单独的对应键,而不是刷新整个会话。要获取当前的保护会话名称(上例中的会话密钥),我们可以使用保护方法: https://github.com/laravel/framework/blob/5.4/src/Illuminate/Auth/SessionGuard.php#L622
现在我们拥有执行此任务所需的一切。这是我目前正在进行的项目的示例:
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 ...
}
使用LoginController::logout 方法,我们用我们的自定义覆盖特征注销(默认的 Laravel 注销逻辑),几乎相同,但允许我们注销单个用户。
相同的逻辑适用于我们所有的登录控制器,具体取决于我们有多少不同的守卫。
我刚刚完成了这个解决方案,经过快速测试,它似乎工作正常,但请在实施前仔细检查。
【讨论】:
我不知道它是否会起作用,但你可以尝试:
// get current user
$user = Auth::user();
// logout user
$userToLogout = User::find(5);
Auth::setUser($userToLogout);
Auth::logout();
// set again current user
Auth::setUser($user);
【讨论】:
我认为最快的解决方案是在用户数据库表中添加一个标志,例如布尔列to_logout,然后在 Auth 中间件中添加类似这样的代码。
$user = Auth::user();
if($user->to_logout){
Auth::logout();
$user->update(['to_update' => 0]);
return redirect('/');
}
【讨论】:
查看docs,似乎没有任何内置功能,类似的请求有been proposed,它还描述了跟踪在多个会话上打开多个会话的单个用户的问题设备。
我相信您将需要创建一个自定义解决方案,例如(如@Dinar 所述)如果您将用户会话存储在数据库中,那么您可以在满足特定条件时检索并销毁特定用户的会话 - 更改他们的密码。
【讨论】:
如果您使用 Laravel 5.2,您可以将会话存储引擎更改为数据库。在这种情况下,每个会话记录也将包含用户 ID。
您只需要从数据库中删除相应的行。
【讨论】: