javaabu/efaas-socialite

eFaas Provider for Laravel Socialite

v3.5.1 2024-07-02 07:45 UTC

README

Latest Version on Packagist Test Status Code Coverage Badge Total Downloads

Laravel Socialite 的 eFaas 提供商,针对 eFaas

注意:本包的当前版本基于 eFaas 文档版本 2.2

要求

本包需要以下依赖项

  • Laravel 6.0 或更高版本
  • PHP 7.4 或更高版本
  • ext-openssl PHP 扩展

安装

对于 Laravel 6.0 及更高版本,您可以通过 composer 安装此包

composer require javaabu/efaas-socialite

对于 Laravel 5.6,请使用 1.x 版本

composer require javaabu/efaas-socialite:^1.0

将配置添加到您的 .env 文件中

将以下配置添加到您的 .env 文件中

EFAAS_CLIENT_ID=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
EFAAS_CLIENT_SECRET=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
EFAAS_REDIRECT_URI=https://your-app.com/path/to/efaas/callback
EFAAS_MODE=development

# for production use
#EFAAS_MODE=production

发布配置文件

可选地,您也可以将配置文件发布到 config/efaas.php

php artisan vendor:publish --provider="Javaabu\EfaasSocialite\Providers\EfaasSocialiteServiceProvider" --tag="efaas-config"

这是配置文件的默认内容

<?php

return [

    /**
     * eFaas client config
     */
    'client' => [
        /**
         * eFaas Client ID
         */
        'client_id' => env('EFAAS_CLIENT_ID'),

        /**
         * eFaas Client Secret
         */
        'client_secret' => env('EFAAS_CLIENT_SECRET'),

        /**
         * eFaas Redirect url
         */
        'redirect' => env('EFAAS_REDIRECT_URI'),

        /**
         * Development mode
         * supports "production" and "development"
         */
        'mode' => env('EFAAS_MODE', 'development'),

        /**
         * Default scopes for the eFaas client
         */
        'scopes' => [
            'openid',
            'efaas.profile',
            'efaas.birthdate',
            'efaas.email',
            'efaas.mobile',
            'efaas.photo',
            'efaas.permanent_address',
            'efaas.country',
            'efaas.passport_number',
            'efaas.work_permit_status'
        ],
    ],

    /*
     * This model will be used to store efaas session sids
     * The class must implement \Javaabu\EfaasSocialite\Contracts\EfaasSessionContract
     */
    'session_model' => \Javaabu\EfaasSocialite\Models\EfaasSession::class,

    /*
     * This handler will be used to manage saving and destroying efaas session records
     * The class must implement \Javaabu\EfaasSocialite\Contracts\EfaasSessionHandlerContract
     */
    'session_handler' => \Javaabu\EfaasSocialite\EfaasSessionHandler::class,

    /*
     * This is the name of the table that will be created by the migration and
     * used by the EfaasSession model shipped with this package.
     */
    'table_name' => 'efaas_sessions',

    /*
     * This is the database connection that will be used by the migration and
     * the EfaasSession model shipped with this package. In case it's not set
     * Laravel's database.default will be used instead.
     */
    'database_connection' => env('EFAAS_SESSIONS_DB_CONNECTION'),
];

发布迁移文件

本包包含用于 efaas_sessions 表的迁移,可用于实现后通道注销。您可以使用以下 Artisan 命令发布这些迁移

php artisan vendor:publish --provider="Javaabu\EfaasSocialite\Providers\EfaasSocialiteServiceProvider" --tag="efaas-migrations"

发布迁移后,您可以运行它们

php artisan migrate

使用方法

注意:本包的演示实现可在 此处 获取。

现在您应该能够像通常使用 Socialite 一样使用提供程序(假设您已安装了外观)。有关更多信息,请参阅 官方 Social 文档

警告:如果您在 Laravel 应用请求 eFaas 授权端点时遇到 403 Forbidden 错误,请请求 NCIT 将您的服务器 IP 地址列入白名单。

return Socialite::driver('efaas')->redirect();

并在您的回调处理程序中,您可以如此访问用户数据。请记住保存用户的 id_tokensid(会话 ID)。

$efaas_user = Socialite::driver('efaas')->user();
$id_token = $efaas_user->id_token;
$sid = $efaas_user->sid;

session()->put('efaas_id_token', $id_token);
session()->put('efaas_sid', $sid);

启用 PKCE

默认情况下,此包已禁用 PKCE。要启用 PKCE,请在您的重定向调用和回调处理程序中分别使用 enablePKCE() 方法。

return Socialite::driver('efaas')->enablePKCE()->redirect();
// inside callback handler
$efaas_user = Socialite::driver('efaas')->enablePKCE()->user();

注销 eFaas 用户

在您的 Laravel 注销重定向中,使用在登录过程中保存的 ID 令牌,使用提供程序的 logOut() 方法进行重定向

$id_token = session('id_token');
return Socialite::driver('efaas')->logOut($id_token, $post_logout_redirect_url);

注意:由于 id_token 可能非常长,在重定向时可能会遇到 nginx 错误。要修复此问题,您可以将以下内容添加到您的 nginx 配置中。更多信息请点击 这里

fastcgi_buffers 16 16k;
fastcgi_buffer_size 32k;

使用 eFaas One-tap 登录

此包将自动将 /efaas-one-tap-login 端点添加到您的 Web 路由中,该端点将重定向到 eFaas 并使用 eFaas 登录代码。

有时您可能希望自定义 Efaas 提供商定义的路由。为了实现这一点,您首先需要在您的应用程序的 AppServiceProvider 的 register 方法中添加 EfaasProvider::ignoreRoutes 来忽略 Efaas 提供商注册的路由

use Javaabu\EfaasSocialite\EfaasProvider;

/**
 * Register any application services.
 */
public function register(): void
{
    EfaasProvider::ignoreRoutes();
}

然后,您可以将 Efaas 提供商在 其路由文件 复制到您的应用程序的 routes/web.php 文件中,并根据您的需求修改它们

Route::group([
    'as' => 'efaas.',
    'namespace' => '\Javaabu\EfaasSocialite\Http\Controllers',
], function () {
    // Efaas routes...
});

实现前通道单点注销

首先,在登录期间,在您的 efaas 回调处理方法中,将用户的 sid(会话 ID)保存到您的会话中。

$efaas_user = Socialite::driver('efaas')->user();
$sid = $efaas_user->sid;

session()->put('efaas_sid', $sid);

然后,在您的单点登出控制器处理方法中,首先使用 eFaas 提供商的 getLogoutSid() 方法检索登出令牌的 sid。如果提供的登出令牌无效,该方法将返回 null。然后,您可以将当前会话中保存的 sid 与检索到的 sid 进行比较,如果它们匹配,则登出用户。

...
public function handleFrontChannelSingleSignOut(Request $request)
{
    $saved_sid = session('efaas_sid');
    $request_sid = Socialite::driver('efaas')->getLogoutSid();
    
    if ($request_sid && $saved_sid == $request_sid) {
        // the logout session matches your saved sid
        // logout your user here
        auth()->guard('web')->logout();
        
        $request->session()->invalidate();
        $request->session()->regenerateToken();
    }     
      
    return redirect()->to('/your-redirect-url')        
}
...

实现后通道单点注销

对于后端登出,您需要使用 Laravel 的 database 会话驱动程序和提供的 efaas_sessions 迁移。

在登录期间,使用 eFaas 提供商的 sessionHandler() 保存用户的 sid(会话 ID)。

$efaas_user = Socialite::driver('efaas')->user();
$sid = $efaas_user->sid;

Socialite::driver('efaas')
    ->sessionHandler()
    ->saveSid($sid);

然后,在您的单点登出控制器处理方法中,首先使用 eFaas 提供商的 getLogoutSid() 方法检索登出令牌的 sid。如果提供的登出令牌无效,该方法将返回 null。然后,您可以使用 eFaas 提供商的 sessionHandler() 来登出所有与 sid 匹配的 Laravel 会话。

...
public function handleBackChannelSingleSignOut(Request $request)
{    
    $sid = Socialite::driver('efaas')->getLogoutSid();
    
    if ($sid) {
        Socialite::driver('efaas')
            ->sessionHandler()
            ->logoutSessions($sid);
    }
    
    // for back channel logout you must return 200 OK response
    return response()->json([
        'success' => ! empty($request_sid)  
    ]);    
}
...

从移动应用进行身份验证

要验证来自移动应用程序的用户,请通过移动应用程序上的 Web View 将用户重定向到 eFaas 登录屏幕。然后在用户登录 eFaas 后,从您的网站重定向他们时截获 code(授权代码)。

一旦您的移动应用程序收到授权代码,请将其发送到您的 API 端点。然后,您可以使用以下方式在服务器端使用授权代码获取 eFaas 用户详细信息。请记住,由于重定向是从您的服务器外部发起的,因此请使用 stateless() 选项。

$efaas_user = Socialite::driver('efaas')->stateless()->userFromCode($code);

收到 eFaas 用户后,您可以根据您用于 API 的任何身份验证方案颁发自己的访问令牌或 API 密钥。

更改 eFaas 登录提示行为

可以通过修改重定向请求中的提示选项来自定义 eFaas 登录提示行为。

return Socialite::driver('efaas')->with(['prompt' => 'select_account'])->redirect();

可用的提示选项包括

eFaas 提供商的可用方法

$provider = Socialite::driver('efaas');

$provider->parseJWT($token); // Parses a JWT token string into a Lcobucci\JWT\Token
$provider->getSidFromToken($token); // Validates a given JWT token and returns the sid from the token
$provider->getJwksResponse(false); // Returns the JWKs (JSON Web Keys) response as an array from the eFaas API. Optionally return the response as a json string using the optional boolean argument
$provider->getPublicKey('5CDA5CF378397733DD33EFBDA82D0F317DCC1D53RS256'); // Returns the public key from JWKs for the given key id as a PEM key string  

eFaas 用户可用方法和公共属性

$efaas_user->isMaldivian(); // Check if is a Maldivian
$efaas_user->getDhivehiName(); // Full name in Dhivehi
$efaas_user->getPhotoMimetype(); // Get the mimetype of the user photo
$efaas_user->getPhotoExtension(); // Get the file extension of the user photo
$efaas_user->getPhotoBase64(); // Get the user photo as a base64 encoded string
$efaas_user->getPhotoDataUrl(); // Get the user photo as a data url
$efaas_user->savePhoto('photo', './path/to/save'); // Saves the user photo to ./path/to/save/photo.jpg and returns the full file path
$efaas_user->getAvatar(); // Alias of getPhotoBase64()
$efaas_user->sid; // Session id of the user
$efaas_user->id_token; // ID Token of the user
$efaas_user->token; // Access token of the user

更改 eFaas 请求作用域

默认情况下,此包会将所有可用的作用域添加到 eFaas 重定向中。您可以通过发布包配置文件并更改作用域来修改默认作用域。要按请求自定义作用域,您可以在重定向期间覆盖作用域。

return Socialite::driver('efaas')->setScopes(['efaas.openid', 'efaas.profile'])->redirect();

从 eFaas 用户对象获取 eFaas 数据

$id_number = $oauth_user->idnumber;

eFaas 可用数据字段

不同的作用域与不同的数据相关联。默认情况下,包括所有作用域,因此您应该能够获取所有数据字段。

作用域: efaas.openid
作用域: efaas.profile
作用域: efaas.email
作用域: efaas.mobile
作用域: efaas.birthdate
作用域: efaas.photo
作用域: efaas.work_permit_status
作用域: efaas.passport_number
作用域: efaas.country
作用域: efaas.permanent_address

以下是 EfaasAddress 对象的字段

EfaasAddress 类还具有以下方法

$permanent_address = $efaas_user->permanent_address;

$permanent_address->getFormattedAddress(); // Get the address with the ward abbreviation. eg: M. Blue Light
$permanent_address->getDhivehiFormattedAddress(); // Get the address in Dhivehi with the ward abbreviation. eg: މ. ބުލޫ ލައިޓް

测试

您可以使用以下方式运行测试

./vendor/bin/phpunit

更新日志

有关最近更改的更多信息,请参阅 更改日志

贡献

有关详细信息,请参阅 贡献指南

安全

如果您发现任何安全问题,请通过电子邮件发送到 info@javaabu.com,而不是使用问题跟踪器。

致谢

许可

MIT 许可证 (MIT)。有关更多信息,请参阅 许可文件