Hej! 是一个简单的 Socialite 认证样板。

资助包维护!
rennokki


README

CI codecov StyleCI Latest Stable Version Total Downloads Monthly Downloads License

Hej! 是 Socialite 简单认证流程的实现。Hej! 默认可以帮助您通过 Socialite 提供商登录和注册用户,或通过扩展控制器链接和取消链接社交账户。

🤝 支持

如果您在生产应用程序、演示、爱好项目、学校项目等中使用 Renoki Co. 的一个或多个开源软件包,请通过 GitHub Sponsors 支持我们的工作。 📦

🚀 安装

您可以通过 composer 安装此软件包

composer require renoki-co/hej

发布配置

$ php artisan vendor:publish --provider="RenokiCo\Hej\HejServiceProvider" --tag="config"

发布迁移

$ php artisan vendor:publish --provider="RenokiCo\Hej\HejServiceProvider" --tag="migrations"

🙌 使用

对于用户(或任何可认证实例),您应该添加 HasSocialAccounts 特性和 Sociable 接口

use RenokiCo\Hej\Concerns\HasSocialAccounts;
use RenokiCo\Hej\Contracts\Sociable;

class User extends Authenticatable implements Sociable
{
    use HasSocialAccounts;

    //
}

Hej! 默认情况下与任何 Laravel 应用程序兼容。

配置 Socialite 后,您只需将所需的重定向和回调路径指向包控制器即可。

Route::get('/social/{provider}/redirect', [\RenokiCo\Hej\Http\Controllers\SocialController::class, 'redirect']);
Route::get('/social/{provider}/callback', [\RenokiCo\Hej\Http\Controllers\SocialController::class, 'callback']);

Route::middleware('auth')->group(function () {
    Route::get('/social/{provider}/link', [\RenokiCo\Hej\Http\Controllers\SocialController::class, 'link']);
    Route::get('/social/{provider}/unlink', [\RenokiCo\Hej\Http\Controllers\SocialController::class, 'unlink']);
});

路径可以是任意的,只要它们包含一个参数,该参数将用于尝试认证的提供者。例如,访问此链接将重定向到 GitHub

https://my-link.com/social/github/redirect

扩展控制器

Hej! 非常灵活,并在后台执行许多操作以使用 Socialite 进行注册或登录。

但是,您需要扩展控制器,然后您可以替换一些方法来自定义流程。

use RenokiCo\Hej\Http\Controllers\SocialController;

class MySocialController extends SocialController
{
    //
}

然后,您应该将路由指向新的控制器。

提供者白名单

由于端点对所有提供者开放,您可以为可使用的 Socialite 提供者名称创建白名单。

/**
 * Whitelist social providers to be used.
 *
 * @var array
 */
protected static $allowedSocialiteProviders = [
    //
];

例如,仅允许 Facebook 和 GitHub 应该如下所示

protected static $allowedSocialiteProviders = [
    'facebook',
    'github',
];

如果通过 URL 访问的提供者之一未列入白名单,则会自动执行简单的重定向。但是,您可以替换它并重定向到您自定义的 重定向操作

自定义 Socialite 重定向和检索

使用 Socialite,您可以使用 ->redirect() 重定向用户,并使用 ->user() 获取它。您可以通过替换 getSocialiteRedirectgetSocialiteUser 来自定义实例。

以下是默认配置

/**
 * Get the Socialite direct instance that will redirect
 * the user to the right provider OAuth page.
 *
 * @param  \Illuminate\Http\Request  $request
 * @param  string  $provider
 * @return mixed
 */
protected function getSocialiteRedirect(Request $request, string $provider)
{
    return $this->socialite
        ->driver($provider)
        ->redirect();
}

/**
 * Get the Socialite User instance that will be
 * given after the OAuth authorization passes.
 *
 * @param  \Illuminate\Http\Request  $request
 * @param  string  $provider
 * @return \Laravel\Socialite\AbstractUser
 */
protected function getSocialiteUser(Request $request, string $provider)
{
    return $this->socialite
        ->driver($provider)
        ->user();
}

注册新用户

当用户登录的社交账户未在数据库中注册时,它会创建一个新的可认证模型,但为了做到这一点,它应该填充数据。

默认情况下,它使用 Socialite 提供商提供的数据填充,并设置一个随机的 64 位字母密码。

/**
 * Get the Authenticatable model data to fill on register.
 * When the user gets created, it will receive these parameters
 * in the `::create()` method.
 *
 * @param  \Illuminate\Http\Request  $request
 * @param  string  $provider
 * @param  \Laravel\Socialite\AbstractUser  $providerUser
 * @return array
 */
protected function getRegisterData(Request $request, string $provider, $providerUser): array
{
    return [
        'name' => $providerUser->getName(),
        'email' => $providerUser->getEmail(),
        'email_verified_at' => now(),
        'password' => Hash::make(Str::random(64)),
    ];
}

处理重复的电子邮件地址

有时,用户可能会创建一个仅使用电子邮件地址创建的账户,没有任何社交账户。在回调时,具有相同电子邮件地址的新社交账户将触发数据库中的新可认证记录。

为此,执行一个 重定向 来处理此特定场景。

填充社交表

注册或登录后,Socialite 数据会创建或更新,无论用户是否存在。

默认情况下,建议不要覆盖,除非您想更改表结构并扩展在 config/hej.php 中设置的 Social 模型。

/**
 * Get the Social model data to fill on register or login.
 *
 * @param  \Illuminate\Http\Request  $request
 * @param  string  $provider
 * @param  \Illuminate\Database\Eloquent\Model  $model
 * @param  \Laravel\Socialite\AbstractUser  $providerUser
 * @return array
 */
protected function getSocialData(Request $request, string $provider, $model, $providerUser): array
{
    return [
        'provider_nickname' => $providerUser->getNickname(),
        'provider_name' => $providerUser->getName(),
        'provider_email' => $providerUser->getEmail(),
        'provider_avatar' => $providerUser->getAvatar(),
    ];
}

回调

在用户认证成功或成功注册之前,存在触发回调,您可以替换它们以实现自定义逻辑。

/**
 * Handle the callback after the registration process.
 *
 * @param  \Illuminate\Http\Request  $request
 * @param  \Illuminate\Database\Eloquent\Model  $model
 * @param  \Illuminate\Database\Eloquent\Model  $social
 * @param  \Laravel\Socialite\AbstractUser  $providerUser
 * @return void
 */
protected function registered(Request $request, $model, $social, $providerUser)
{
    //
}

/**
 * Handle the callback after the login process.
 *
 * @param  \Illuminate\Http\Request  $request
 * @param  \Illuminate\Database\Eloquent\Model  $model
 * @param  \Illuminate\Database\Eloquent\Model  $social
 * @param  \Laravel\Socialite\AbstractUser  $providerUser
 * @return void
 */
protected function authenticated(Request $request, $model, $social, $providerUser)
{
    //
}

/**
 * Handle the callback after the linking process.
 *
 * @param  \Illuminate\Http\Request  $request
 * @param  \Illuminate\Database\Eloquent\Model  $model
 * @param  \Illuminate\Database\Eloquent\Model  $social
 * @param  \Laravel\Socialite\AbstractUser  $providerUser
 * @return void
 */
protected function linked(Request $request, $model, $social, $providerUser)
{
    //
}

/**
 * Handle the callback after the unlink process.
 *
 * @param  \Illuminate\Http\Request  $request
 * @param  \Illuminate\Database\Eloquent\Model  $model
 * @param  string  $provider
 * @return void
 */
protected function unlinked(Request $request, $model, string $provider)
{
    //
}

重定向

您可以在控制器中自由覆盖操作的跳转。

use Illuminate\Support\Facades\Redirect;
use Illuminate\Support\Facades\Session;

/**
 * Specify the redirection route after successful authentication.
 *
 * @param  \Illuminate\Database\Eloquent\Model  $model
 * @return \Illuminate\Http\RedirectResponse
 */
protected function redirectToAfterAuthentication($model)
{
    return Redirect::route('home');
}

/**
 * Specify the redirection route to let the users know
 * the authentication using the selected provider was rejected.
 *
 * @param  \Illuminate\Http\Request  $request
 * @param  string  $provider
 * @return \Illuminate\Http\RedirectResponse
 */
protected function redirectToAfterProviderIsRejected(Request $request, $provider)
{
    return Redirect::route('home');
}

/**
 * Specify the redirection route to let the users know
 * the E-Mail address used with this social account is
 * already existent as another account. This is most often
 * occuring during registrations with Social accounts.
 *
 * @param  \Illuminate\Http\Request  $request
 * @param  string  $provider
 * @param  \Laravel\Socialite\AbstractUser  $providerUser
 * @return \Illuminate\Http\RedirectResponse
 */
protected function redirectToAfterDuplicateEmail(Request $request, $provider, $providerUser)
{
    return Redirect::route('home');
}

链接和取消链接

在创建新账户或使用 Socialite 提供者登录之前,Hej! 支持将社交账户链接到您的用户或从您的用户解除链接。

您需要确保只有经过认证的用户才能访问路由。

Route::middleware('auth')->group(function () {
    Route::get('/social/{provider}/link', [\RenokiCo\Hej\Http\Controllers\SocialController::class, 'link']);
    Route::get('/social/{provider}/unlink', [\RenokiCo\Hej\Http\Controllers\SocialController::class, 'unlink']);
});

此外,您可以访问用于链接或解除链接提供者的 URL。

另外,您可以在链接/解除链接过程中发生的事件中实现自定义重定向。

use Illuminate\Support\Facades\Redirect;
use Illuminate\Support\Facades\Session;

/**
 * Specify the redirection route to let the users know
 * the social account is already associated with their account.
 *
 * @param  \Illuminate\Http\Request  $request
 * @param  string  $provider
 * @param  \Illuminate\Database\Eloquent\Model  $model
 * @return \Illuminate\Http\RedirectResponse
 */
protected function redirectToAfterProviderIsAlreadyLinked(Request $request, $provider, $model)
{
    return Redirect::route('home');
}

/**
 * Specify the redirection route to let the users know
 * the social account is associated with another account.
 *
 * @param  \Illuminate\Http\Request  $request
 * @param  string  $provider
 * @param  \Illuminate\Database\Eloquent\Model  $model
 * @param  \Laravel\Socialite\AbstractUser  $providerUser
 * @return \Illuminate\Http\RedirectResponse
 */
protected function redirectToAfterProviderAlreadyLinkedByAnotherAuthenticatable(
    Request $request, $provider, $model, $providerUser
) {
    return Redirect::route('home');
}

/**
 * Specify the redirection route to let the users know
 * they linked the social account.
 *
 * @param  \Illuminate\Http\Request  $request
 * @param  \Illuminate\Database\Eloquent\Model  $model
 * @param  \Illuminate\Database\Eloquent\Model  $social
 * @param  \Laravel\Socialite\AbstractUser  $providerUser
 * @return \Illuminate\Http\RedirectResponse
 */
protected function redirectToAfterLink(Request $request, $model, $social, $providerUser)
{
    return Redirect::route('home');
}

/**
 * Specify the redirection route to let the users
 * they have unlinked the social account.
 *
 * @param  \Illuminate\Http\Request  $request
 * @param  \Illuminate\Database\Eloquent\Model  $model
 * @param  string  $provider
 * @return \Illuminate\Http\RedirectResponse
 */
protected function redirectToAfterUnlink(Request $request, $model, string $provider)
{
    return Redirect::route('home');
}

自定义可认证的

在尝试登录或注册时,该软件包使用在 config/hej.php 中定义的默认 App\User。然而,这可以在请求级别轻松替换。

/**
 * Get the model to login (or register).
 *
 * @param  \Illuminate\Http\Request  $request
 * @param  string  $provider
 * @return string
 */
public function getAuthenticatable(Request $request, string $provider)
{
    return config('hej.default_authenticatable');
}

例如,您可以将模型更改为用于不同 Socialite 提供者的认证。

public function getAuthenticatable(Request $request, string $provider)
{
    if ($provider === 'medium') {
        return \App\AnotherUser::class;
    }

    return config('hej.default_authenticatable');
}

请注意,该模型还应使用特性(Trait)和接口,并实现 Authenticatable

🐛 测试

vendor/bin/phpunit

🤝 贡献

有关详细信息,请参阅 CONTRIBUTING

🔒 安全

如果您发现任何安全相关的问题,请通过电子邮件 alex@renoki.org 联系,而不是使用问题跟踪器。

🎉 致谢