Laravel房产代理平台:限制同一用户账号同时登录次数需求
Hey there! Let's tackle this concurrent login restriction problem for your Laravel real estate platform. I've dealt with similar SaaS account-sharing scenarios before, so here's a practical, tailored solution to stop personal account misuse:
The goal is to track active sessions per user, enforce a session limit based on their account type, and either block new logins or invalidate old sessions when the limit is hit. We'll leverage Laravel's session system and a database table (or cache) to keep tabs on active sessions.
1. Set Up Session Tracking (Database Option)
First, create a table to link users to their active sessions. Run this Artisan command:
php artisan make:migration create_user_sessions_table
Update the migration file with this schema:
public function up() { Schema::create('user_sessions', function (Blueprint $table) { $table->id(); $table->foreignId('user_id')->constrained()->onDelete('cascade'); $table->string('session_id')->unique(); $table->timestamp('last_activity')->useCurrent(); $table->timestamps(); }); }
Run the migration:
php artisan migrate
Then create a corresponding model:
php artisan make:model UserSession
2. Modify Login Logic to Enforce Limits
Override the authenticated method in your LoginController (usually in app/Http/Controllers/Auth/LoginController.php) to handle session checks:
use App\Models\UserSession; use Illuminate\Support\Facades\Session; use Carbon\Carbon; protected function authenticated(Request $request, $user) { // Fetch account-specific session limits from config $maxSessions = config('app.concurrent_sessions.' . $user->account_type); // Clean up expired sessions first to avoid false counts UserSession::where('user_id', $user->id) ->where('last_activity', '<', Carbon::now()->subMinutes(config('session.lifetime'))) ->delete(); // Count active valid sessions $activeSessionCount = UserSession::where('user_id', $user->id)->count(); if ($activeSessionCount >= $maxSessions) { // Option 1: Kick the oldest active session (most user-friendly) $oldestSession = UserSession::where('user_id', $user->id) ->orderBy('last_activity') ->first(); if ($oldestSession) { // Destroy the old session Session::getHandler()->destroy($oldestSession->session_id); $oldestSession->delete(); } // Option 2: Block new login (uncomment below if you prefer strict enforcement) // auth()->logout(); // return redirect()->back()->withErrors([ // 'email' => 'Your account has reached the maximum number of concurrent logins. Please log out from another device first.' // ]); } // Record the current session UserSession::updateOrCreate( ['user_id' => $user->id, 'session_id' => session()->getId()], ['last_activity' => Carbon::now()] ); return redirect()->intended($this->redirectPath()); }
3. Configure Account-Specific Limits
Add these settings to your config/app.php file for easy adjustment:
'concurrent_sessions' => [ 'personal' => 1, // Restrict personal accounts to 1 concurrent login 'enterprise' => 10, // Allow enterprise accounts 10 concurrent logins (adjust as needed) ],
4. Update Session Activity Timestamps
Create a middleware to keep session activity up-to-date, so we can accurately detect inactive sessions:
php artisan make:middleware UpdateSessionActivity
Edit the middleware file (app/Http/Middleware/UpdateSessionActivity.php):
use App\Models\UserSession; use Carbon\Carbon; public function handle(Request $request, Closure $next) { if (auth()->check()) { UserSession::where('user_id', auth()->id()) ->where('session_id', session()->getId()) ->update(['last_activity' => Carbon::now()]); } return $next($request); }
Register this middleware in app/Http/Kernel.php by adding it to the web middleware group:
protected $middlewareGroups = [ 'web' => [ // ... existing middleware \App\Http\Middleware\UpdateSessionActivity::class, ], ];
5. Clean Up Sessions on Logout
Override the loggedOut method in your LogoutController to remove the session record when a user logs out:
use App\Models\UserSession; protected function loggedOut(Request $request) { if (auth()->check()) { UserSession::where('user_id', auth()->id()) ->where('session_id', session()->getId()) ->delete(); } return redirect('/'); }
User Feedback: Add a flash message to notify users when their session is kicked. For example, in your main layout:
@if(session('session_kicked')) <div class="alert alert-danger"> Your account was logged in from another device, so you've been signed out. </div> @endifModify the session destruction logic to flash this message to the old session for a better user experience.
Cache-Based Tracking: If you prefer not to use a database, replace the
UserSessionmodel with Redis/cache. Store active session IDs in a sorted set (sorted by last activity) for each user, then trim the set to the max session limit when needed.Admin Dashboard: Add a section to let admins view active sessions per user and manually invalidate them if misuse is reported.
内容的提问来源于stack exchange,提问作者sveti petar

