当前位置:首页 > 文章列表 > 文章 > php教程 > LaravelSocialite强制登出教程详解

LaravelSocialite强制登出教程详解

2025-12-11 13:27:35 0浏览 收藏
推广推荐
免费电影APP ➜
支持 PC / 移动端,安全直达

IT行业相对于一般传统行业,发展更新速度更快,一旦停止了学习,很快就会被行业所淘汰。所以我们需要踏踏实实的不断学习,精进自己的技术,尤其是初学者。今天golang学习网给大家整理了《Laravel Socialite单点登录强制登出教程》,聊聊,我们一起来看看吧!

Laravel Socialite单点登录:强制多设备登出实现教程

本文旨在提供一个在Laravel Socialite应用中实现单用户会话、强制多设备登出的专业教程。通过引入设备标识符、优化登录流程以及创建会话验证中间件,确保用户在任何时刻只能在一个设备上保持登录状态,从而提升应用的安全性和用户会话管理能力。

在现代Web应用中,尤其是在使用第三方认证(如Google、Twitter通过Laravel Socialite)的场景下,为了增强账户安全性并确保会话管理的严谨性,常常需要限制用户只能在一个设备上保持登录状态。当用户从新设备登录时,其在旧设备上的会话应自动失效。本教程将详细阐述如何通过数据库字段、会话管理和自定义中间件来实现这一目标。

1. 数据库结构调整:引入设备标识符

首先,我们需要在 users 表中添加一个字段来存储当前用户登录设备的唯一标识符。这个标识符将在用户每次成功登录时更新。

创建迁移文件:

php artisan make:migration add_device_identifier_to_users_table --table=users

编辑迁移文件:

<?php

use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;

class AddDeviceIdentifierToUsersTable extends Migration
{
    /**
     * Run the migrations.
     *
     * @return void
     */
    public function up()
    {
        Schema::table('users', function (Blueprint $table) {
            $table->string('current_device_identifier')->nullable()->after('remember_token');
        });
    }

    /**
     * Reverse the migrations.
     *
     * @return void
     */
    public function down()
    {
        Schema::table('users', function (Blueprint $table) {
            $table->dropColumn('current_device_identifier');
        });
    }
}

运行迁移:

php artisan migrate

current_device_identifier 字段将用于存储用户当前活跃会话的设备标识。

2. 登录流程优化:生成并存储设备标识

在用户通过Laravel Socialite成功认证并登录后,我们需要生成一个唯一的设备标识符,将其存储到 users 表中,并同时将其写入到当前用户的会话(或JWT令牌)中。

生成设备标识符的策略:

设备标识符可以是一个简单的UUID,也可以是基于用户代理(User-Agent)和IP地址的哈希值,以提供更强的设备关联性。为了简化,这里我们使用一个随机字符串。

修改 Socialite 回调逻辑:

假设您的 Socialite 回调逻辑位于 AuthController 或类似的控制器中。

<?php

namespace App\Http\Controllers\Auth;

use App\Http\Controllers\Controller;
use App\Models\User;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Str;
use Laravel\Socialite\Facades\Socialite;

class SocialLoginController extends Controller
{
    /**
     * Redirect the user to the social provider authentication page.
     *
     * @param string $provider
     * @return \Symfony\Component\HttpFoundation\RedirectResponse
     */
    public function redirectToProvider($provider)
    {
        return Socialite::driver($provider)->redirect();
    }

    /**
     * Obtain the user information from the social provider.
     *
     * @param string $provider
     * @return \Illuminate\Http\RedirectResponse
     */
    public function handleProviderCallback($provider)
    {
        try {
            $socialUser = Socialite::driver($provider)->user();
        } catch (\Exception $e) {
            return redirect('/login')->withErrors(['social_login' => '无法通过 ' . ucfirst($provider) . ' 登录,请重试。']);
        }

        $user = User::where('provider_id', $socialUser->getId())
                    ->where('provider', $provider)
                    ->first();

        if (!$user) {
            // 如果用户不存在,则创建新用户
            $user = User::create([
                'name' => $socialUser->getName(),
                'email' => $socialUser->getEmail(),
                'provider' => $provider,
                'provider_id' => $socialUser->getId(),
                // ... 其他字段
            ]);
        }

        // 生成新的设备标识符
        $deviceIdentifier = Str::random(60);

        // 更新用户表中的设备标识符
        $user->update([
            'current_device_identifier' => $deviceIdentifier,
        ]);

        // 登录用户
        Auth::login($user, true);

        // 将设备标识符存储到当前会话中
        session(['device_identifier' => $deviceIdentifier]);

        return redirect()->intended('/home');
    }

    /**
     * Log the user out of the application.
     *
     * @return \Illuminate\Http\RedirectResponse
     */
    public function logout()
    {
        Auth::logout();
        session()->forget('device_identifier'); // 清除会话中的设备标识符
        request()->session()->invalidate();
        request()->session()->regenerateToken();

        return redirect('/');
    }
}

在上述代码中:

  1. 我们生成了一个随机字符串作为 deviceIdentifier。
  2. 将此标识符更新到 users 表的 current_device_identifier 字段中。
  3. 在用户登录成功后,将相同的 deviceIdentifier 存储到当前用户的会话 (session) 中。

3. 创建并应用会话验证中间件

现在,我们需要一个中间件来在每次请求时验证当前会话中的 device_identifier 是否与数据库中存储的 current_device_identifier 匹配。如果不匹配,则意味着用户已从其他设备登录,当前会话应被强制登出。

创建中间件:

php artisan make:middleware EnsureSingleSession

编辑 app/Http/Middleware/EnsureSingleSession.php:

<?php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;

class EnsureSingleSession
{
    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return \Illuminate\Http\Response|\Illuminate\Http\RedirectResponse
     */
    public function handle(Request $request, Closure $next)
    {
        if (Auth::check()) {
            $user = Auth::user();
            $sessionDeviceIdentifier = session('device_identifier');

            // 检查数据库中的设备标识符是否与会话中的匹配
            // 如果数据库中的为空,或者与会话中的不匹配,则强制登出
            if (empty($user->current_device_identifier) || $user->current_device_identifier !== $sessionDeviceIdentifier) {
                Auth::logout(); // 强制登出当前用户
                $request->session()->invalidate(); // 使会话失效
                $request->session()->regenerateToken(); // 重新生成CSRF令牌

                // 可以重定向到登录页并附带提示信息
                return redirect('/login')->withErrors(['session_expired' => '您已从其他设备登录,当前会话已失效。请重新登录。']);
            }
        }

        return $next($request);
    }
}

注册中间件:

打开 app/Http/Kernel.php 文件,将 EnsureSingleSession 中间件添加到 web 中间件组中,确保它在所有需要保护的Web路由上运行。

protected array $middlewareGroups = [
    'web' => [
        \App\Http\Middleware\EncryptCookies::class,
        \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
        \Illuminate\Session\Middleware\StartSession::class,
        // \Illuminate\Session\Middleware\AuthenticateSession::class, // 如果使用,确保在自定义中间件之前
        \Illuminate\View\Middleware\ShareErrorsFromSession::class,
        \App\Http\Middleware\VerifyCsrfToken::class,
        \Illuminate\Routing\Middleware\SubstituteBindings::class,
        \App\Http\Middleware\EnsureSingleSession::class, // 添加到这里
    ],

    'api' => [
        // \Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
        'throttle:api',
        \Illuminate\Routing\Middleware\SubstituteBindings::class,
    ],
];

将中间件添加到 web 组后,所有使用 web 路由中间件的路由都将受到此单会话验证的保护。

注意事项

  • 设备标识符的生成策略: 上述示例使用了简单的随机字符串。在生产环境中,您可以考虑使用更复杂的策略,例如结合 request()->header('User-Agent') 和 request()->ip() 的哈希值,以更好地识别“设备”。然而,请注意IP地址和User-Agent的变动性(如移动网络IP切换、浏览器更新User-Agent)。UUID或加密的随机字符串通常是更可靠的选择。
  • 用户体验: 突然的登出可能会让用户感到困惑。可以在重定向到登录页时提供清晰的提示信息,解释登出的原因。
  • API认证(JWT/Sanctum): 如果您的应用还使用JWT或Laravel Sanctum进行API认证,此逻辑需要进行相应调整。JWT通常是无状态的,但您可以在JWT的Payload中包含 device_identifier,并在每次请求时通过中间件验证该Payload中的标识符是否与数据库中的匹配。
  • 会话失效时间: Laravel的会话默认有过期时间。此机制与会话过期机制是互补的,即使会话未过期,如果用户从新设备登录,旧设备也会被强制登出。
  • 登出逻辑: 确保在用户主动登出时,也清除会话中的 device_identifier,并根据需要清除数据库中的 current_device_identifier(设置为 null 或更新为新值)。

总结

通过在 users 表中存储设备标识符、在登录时更新此标识符并将其写入会话,以及通过自定义中间件在每次请求时进行验证,我们成功地为Laravel Socialite应用构建了一个强制单用户会话和多设备登出策略。这不仅提升了应用安全性,也为用户提供了更清晰的会话管理体验。这种方法是实现账户安全和会话控制的有效实践。

文中关于的知识介绍,希望对你的学习有所帮助!若是受益匪浅,那就动动鼠标收藏这篇《LaravelSocialite强制登出教程详解》文章吧,也可关注golang学习网公众号了解相关技术文章。

邮政快递运输时间解析邮政快递运输时间解析
上一篇
邮政快递运输时间解析
EyeCare护眼过滤功能怎么开启
下一篇
EyeCare护眼过滤功能怎么开启
查看更多
最新文章
查看更多
课程推荐
  • 前端进阶之JavaScript设计模式
    前端进阶之JavaScript设计模式
    设计模式是开发人员在软件开发过程中面临一般问题时的解决方案,代表了最佳的实践。本课程的主打内容包括JS常见设计模式以及具体应用场景,打造一站式知识长龙服务,适合有JS基础的同学学习。
    543次学习
  • GO语言核心编程课程
    GO语言核心编程课程
    本课程采用真实案例,全面具体可落地,从理论到实践,一步一步将GO核心编程技术、编程思想、底层实现融会贯通,使学习者贴近时代脉搏,做IT互联网时代的弄潮儿。
    516次学习
  • 简单聊聊mysql8与网络通信
    简单聊聊mysql8与网络通信
    如有问题加微信:Le-studyg;在课程中,我们将首先介绍MySQL8的新特性,包括性能优化、安全增强、新数据类型等,帮助学生快速熟悉MySQL8的最新功能。接着,我们将深入解析MySQL的网络通信机制,包括协议、连接管理、数据传输等,让
    500次学习
  • JavaScript正则表达式基础与实战
    JavaScript正则表达式基础与实战
    在任何一门编程语言中,正则表达式,都是一项重要的知识,它提供了高效的字符串匹配与捕获机制,可以极大的简化程序设计。
    487次学习
  • 从零制作响应式网站—Grid布局
    从零制作响应式网站—Grid布局
    本系列教程将展示从零制作一个假想的网络科技公司官网,分为导航,轮播,关于我们,成功案例,服务流程,团队介绍,数据部分,公司动态,底部信息等内容区块。网站整体采用CSSGrid布局,支持响应式,有流畅过渡和展现动画。
    485次学习
查看更多
AI推荐
  • ChatExcel酷表:告别Excel难题,北大团队AI助手助您轻松处理数据
    ChatExcel酷表
    ChatExcel酷表是由北京大学团队打造的Excel聊天机器人,用自然语言操控表格,简化数据处理,告别繁琐操作,提升工作效率!适用于学生、上班族及政府人员。
    3270次使用
  • Any绘本:开源免费AI绘本创作工具深度解析
    Any绘本
    探索Any绘本(anypicturebook.com/zh),一款开源免费的AI绘本创作工具,基于Google Gemini与Flux AI模型,让您轻松创作个性化绘本。适用于家庭、教育、创作等多种场景,零门槛,高自由度,技术透明,本地可控。
    3483次使用
  • 可赞AI:AI驱动办公可视化智能工具,一键高效生成文档图表脑图
    可赞AI
    可赞AI,AI驱动的办公可视化智能工具,助您轻松实现文本与可视化元素高效转化。无论是智能文档生成、多格式文本解析,还是一键生成专业图表、脑图、知识卡片,可赞AI都能让信息处理更清晰高效。覆盖数据汇报、会议纪要、内容营销等全场景,大幅提升办公效率,降低专业门槛,是您提升工作效率的得力助手。
    3510次使用
  • 星月写作:AI网文创作神器,助力爆款小说速成
    星月写作
    星月写作是国内首款聚焦中文网络小说创作的AI辅助工具,解决网文作者从构思到变现的全流程痛点。AI扫榜、专属模板、全链路适配,助力新人快速上手,资深作者效率倍增。
    4622次使用
  • MagicLight.ai:叙事驱动AI动画视频创作平台 | 高效生成专业级故事动画
    MagicLight
    MagicLight.ai是全球首款叙事驱动型AI动画视频创作平台,专注于解决从故事想法到完整动画的全流程痛点。它通过自研AI模型,保障角色、风格、场景高度一致性,让零动画经验者也能高效产出专业级叙事内容。广泛适用于独立创作者、动画工作室、教育机构及企业营销,助您轻松实现创意落地与商业化。
    3892次使用
微信登录更方便
  • 密码登录
  • 注册账号
登录即同意 用户协议隐私政策
返回登录
  • 重置密码