nickbeen/socialiteproviders-google-one-tap

Laravel Socialite 的 Google One Tap 提供程序

1.0.1 2024-03-15 12:25 UTC

This package is auto-updated.

Last update: 2024-09-06 14:49:22 UTC


README

Latest version Total downloads PHP Version License

这是一个为Laravel Socialite提供的提供程序,允许通过 Google One Tap 进行 Google 身份验证。Google One Tap 框架建立在 OAuth2 之上,但并不使用传统的 OAuth 授权用户流程。它不是返回访问令牌,而是返回一个认证 JWT 令牌,该令牌在一小时后过期。

Google One Tap 不会与您的应用程序会话同步,因此您需要在应用程序中解决此问题。只要用户的凭证未被吊销,并且用户使用 Google 账户或 Google Chrome 浏览器登录,应用程序就能够在需要时通过最小用户交互获取新的 JWT 令牌。

安装

composer require nickbeen/socialiteproviders-google-one-tap

此包依赖于 google/apiclient(包括 200 多个 google\api-clients-services 包)并在安装此包时也会包含在内。

您可以在 composer.json 中运行 google-task-composer-cleanup 脚本来仅保留运行此 Socialite 提供程序所需的 Google API 客户端包。如果您的应用程序依赖于 google/apiclient请勿 运行此脚本。

用法

如果您的应用程序尚未安装 Laravel Socialite,请参阅基本安装指南

设置 Google 项目

首先,您可能需要在Google Cloud 控制台中创建一个新的项目,设置 OAuth 授权屏幕 并创建一个新的 OAuth 客户端 ID。在凭据菜单中,您将找到用于认证的客户端 ID 和客户端密钥。

添加配置

您需要将客户端 ID 和客户端密钥存储在您的 .env 文件中,并将配置添加到 config/services.php。您还需要添加一个重定向 URL,该 URL 将用于使用 Google One Tap 进行登录和注册。此包引用特定的 .env 值,以避免与标准 Google Socialite 提供程序发生冲突。

# .env

GOOGLE_CLIENT_ID=314159265-pi.apps.googleusercontent.com
GOOGLE_CLIENT_SECRET=mkhYkO_ECIIp11mcZ3CEClhmgh_9FWTV2M_
GOOGLE_LOGIN_URI=/auth/google-one-tap
# config/services.php

return [

    // other providers

    'google-one-tap' => [
      'client_id' => env('GOOGLE_CLIENT_ID'),
      'client_secret' => env('GOOGLE_CLIENT_SECRET'),
      'redirect' => env('GOOGLE_LOGIN_URI'),
    ],
];

添加提供程序事件监听器

配置包的监听器以监听 SocialiteWasCalled 事件。在 Laravel 11 中,将事件添加到 app/Providers/AppServiceProvider 中的 boot() 方法,或者在 Laravel 10 中将其添加到 app/Providers/EventServiceProvider 中的 listen[] 数组。有关详细说明,请参阅基本安装指南

使用 Laravel 11

namespace App\Providers;

use Illuminate\Support\Facades\Event;
use Illuminate\Support\ServiceProvider;

class AppServiceProvider extends ServiceProvider
{
    /**
     * Bootstrap any application services.
     */
    public function boot(): void
    {
        Event::listen(function (\SocialiteProviders\Manager\SocialiteWasCalled $event) {
            $event->extendSocialite('google-one-tap', \SocialiteProviders\GoogleOneTap\Provider::class);
        });
    }
}

使用 Laravel 10

namespace App\Providers;

use Illuminate\Support\ServiceProvider;

class EventServiceProvider extends ServiceProvider
{
    protected $listen = [
        \SocialiteProviders\Manager\SocialiteWasCalled::class => [
            // other providers
            \SocialiteProviders\GoogleOneTap\GoogleOneTapExtendSocialite::class,
        ],
    ];
}

用法

Google One Tap 在前端和后端都需要特定的实现。

前端

在每个您想要使用 Google One Tap 的页面上,您需要在 html 模板的头中包含以下脚本。

@guest
    <script src="https://#/gsi/client" async defer></script>
@endguest

实际的 Google One Tap 提示可以通过 JavaScript 或 HTML 来启动。以下代码处理了服务器端的响应。您可以将此代码放置在任意位置。您也可以将 data-client_iddata-login_uri 添加到任何现有的 HTML 元素。有关更多设置和变体,例如完整的 JavaScript 实现,请参阅参考资料

@guest
    <div id="g_id_onload"
         data-auto_select="true"
         data-client_id="{{ config('services.google-one-tap.client_id') }}"
         data-login_uri="{{ config('services.google-one-tap.redirect') }}"
         data-use_fedcm_for_prompt="true">
    </div>
@endguest

由于Google One tap正在迁移到FedCM,因此此元素的风格将不会产生任何效果。这意味着如果浏览器支持它,提示将由浏览器本身处理。

对于注销,您应该在注销按钮上添加g_id_signout类,以避免由于前一个片段中的data-auto_select引起的重定向循环。

<form action="{{ route('logout') }}" method="post">
    @csrf
    <button class="g_id_signout">Sign out</button>
</form>

当用户关闭Google One Tap提示时,Google One Tap有一个冷却期。用户关闭提示的次数越多,提示重新出现在用户面前所需的时间就越长。因此,您需要包含一个登录按钮,以便在Google Sign-In提示的情况下进行回退。您可能只想在登录和注册页面上包含此按钮。只有需要data-type字段。

<div class="g_id_signin"
    data-type="standard">
</div>

后端

Google One Tap建立在OAuth之上,但与使用访问令牌和刷新令牌的方式不同,它使用认证的JTW令牌。在此上下文中不会使用redirect()refreshToken()方法,并将抛出DisallowedMethodException作为提醒。

您的控制器不需要重定向用户,而是可以立即解析令牌,而不是解析用户。

use Laravel\Socialite\Facades\Socialite;

return Socialite::driver('google-one-tap')->userFromToken($token);

此方法将返回JWT令牌的有效负载或如果提供的令牌无效,则抛出InvalidIdTokenException

有效负载数组

请仅使用id字段作为用户的标识符,因为它在所有Google帐户中是唯一的且永远不会重用。不要使用email作为标识符,因为Google帐户可以在不同的时间点拥有多个电子邮件地址。

使用emailemail_verifiedhost_domain字段,您可以确定Google是否托管并具有电子邮件地址的权威性。在Google具有权威性的情况下,可以确认用户是合法帐户所有者。

处理有效负载

包含id的有效负载允许您在用户与Google One Tap提示交互完成后处理用户流程。这通常涉及在Google ID不在您的数据库中时注册用户,或者如果您已注册具有此Google ID的用户,则登录用户。

可选地,您可以使用email检查用户是否已有用户帐户或来自其他提供者的Socialite凭证,并可能连接帐户或通知用户帐户。在基本的Laravel代码中,它可能看起来像这样

// routes/web.php

use App\Controllers\Auth\GoogleOneTapController;
use Illuminate\Support\Facades\Route;

Route::post('auth/google-one-tap', [GoogleOneTapController::class, 'handler'])
    ->middleware('guest')
    ->name('google-one-tap.handler');
// e.g. GoogleOneTapController.php

use App\Models\User;
use Illuminate\Http\Request;
use Laravel\Socialite\Facades\Socialite;
use SocialiteProviders\GoogleOneTap\Exceptions\InvalidIdTokenException;

public function handler(Request $request)
{
    // Verify and validate JWT received from Google One Tap prompt
    try {
        $googleUser = Socialite::driver('google-one-tap')->userFromToken($request->input('credential'));
    } catch (InvalidIdTokenException $exception) {
        return response()->json(['error' => $exception])
    }

    // Log the user in if the Google ID is associated with a user
    if ($googleUser = User::where('google_id', $googleUser['id'])->first()) {
        auth()->login($googleUser);
    }
    
    // Send user to registration form to provide missing details like username
    return redirect()->view('register.google-one-tap', compact('googleUser'))
}

常见问题解答

如何使用具有Google One Tap的权威范围进行例如上传到Google Drive的操作?

Google One Tap只能用于身份验证(你是谁)。对于授权,您需要使用Laravel Socialite的内置Google提供者。这两个提供者可以同时使用,以获得两者的最佳效果。

我能否检查用户是否使用One Tap登录、使用了现有会话等?

Google响应中的select_by字段包含几个可能的值,如autouseruser_1tap,这些值表示用户在注册或登录时如何与您的应用程序交互。在Laravel中,可以在控制器中轻松访问此值。

$select_by = request()->input('select_by')

参考资料

许可证

本软件包遵循MIT许可协议(MIT)。有关详细信息,请参阅许可协议