julidev/laravel-sso-keycloak

该软件包允许您使用 Keycloak 服务器进行用户认证。

dev-master 2024-07-30 01:55 UTC

This package is auto-updated.

Last update: 2024-09-30 02:31:13 UTC


README

该软件包允许您使用 Keycloak 服务器 进行用户认证。

要求

  • 拥有一个 Keycloak 服务器。
  • 已配置领域并且有一个接受认证的客户端。

支持

此软件包已在以下环境中测试:

其他 Keycloak 服务器版本可能无法保证工作。

此项目是开源的,并在我的空闲时间维护。因此,如果您有任何问题,您可以打开一个 Issue 并提供所有详细信息(laravel 版本、keycloak 版本、问题的描述等),我将很乐意尝试帮助您。

流程

  1. 用户访问受保护的路由并被重定向到 Keycloak 登录。
  2. 用户登录并获得一个代码。
  3. 他被重定向到回调页面,我们将代码更改为访问令牌。
  4. 我们将其存储在会话中并验证用户。
  5. 用户已登录。
  6. 我们将用户重定向到 "redirect_url" 路由(参见配置)或目标路由。

安装

需要该软件包

composer require julidev/laravel-sso-keycloak

如果您想更改路由或 Keycloak 的默认值,发布配置文件

php artisan vendor:publish  --provider="Julidev\LaravelSsoKeycloak\IAMGuardServiceProvider"

配置

发布 config/sso-web.php 文件后,您可以更改路由

'redirect_url' => '/admin',

'routes' => [
    'login' => 'sso/login',
    'logout' => 'sso/logout',
    'register' => 'sso/register',
    'callback' => 'sso/callback',
]

修改任何值以更改 URL。

可以更改其他配置以使用新的默认值,但我们建议使用 .env 文件

  • KEYCLOAK_BASE_URL

Keycloak 服务器 URL。通常类似于例如: https://:8080/

  • KEYCLOAK_REALM

Keycloak 领域。默认为 master

  • KEYCLOAK_REALM_PUBLIC_KEY

Keycloak 服务器领域公钥(字符串)。

在 Keycloak 控制台中,转到:Keycloak >> 领域设置 >> 密钥 >> RS256 >> 公钥。

  • KEYCLOAK_CLIENT_ID

Keycloak 客户端 ID。

在 Keycloak 控制台中,转到:Keycloak >> 客户端 >> 设置。

  • KEYCLOAK_CLIENT_SECRET

Keycloak 客户端密钥。如果为空,我们不会将其发送到令牌端点。

在控制台中,转到:Keycloak >> 客户端 >> 设置。

  • KEYCLOAK_CACHE_OPENID

我们可以缓存 OpenId 配置:这是我们需要 Keycloak 的端点列表。

如果您激活它,请记住在更改领域或 URL 时清除缓存。

只需将您希望作为数组添加到 "guzzle_options" 数组的选项,例如在 sso-web.php 配置文件上。例如

Laravel 认证

您应该在 config/app.php 中添加 IAMGuardServiceProvider。

Julidev\LaravelSsoKeycloak\IAMGuardServiceProvider::class

只需将 sso 添加到您想要配置的 "guard" 和 "user_model" 选项中。

由于我的默认是 web,我将其添加到其中

'authentication_defaults' => [

    'enable' => env('KEYCLOAK_AUTH_DEFAULTS', true),
    // Database connection for following tables.
    'connection' => '',

    // User tables and model.
    'users_table' => 'users',
    'users_model' => App\User::class, // e.g
]
'auth' => [
    'guard' => 'web', // e.g

    'guards' => [
        'iam' => [
            'driver'    => 'sso-web',
            'provider'  => 'users-iam',
        ],
    ],
    'providers' => [
        'users-iam' => [
            'driver'    => 'sso-users',
            'model'     => Julidev\LaravelSsoKeycloak\Models\IAMUser::class,
        ],
    ],
],

注意:如果您想使用其他用户模型,请检查 FAQ 中的 "如何实现我的模型?"。

API

我们实现了 Illuminate\Contracts\Auth\Guard。因此,所有 Laravel 默认方法都将可用。

例如:Auth::user() 返回已认证的用户。

角色

您可以通过 Auth::hasRole('role') 检查用户是否有角色;

此方法接受两个参数:第一个是角色(字符串或字符串数组),第二个是资源。

如果没有提供,资源将是 client_id,这是验证您是否正在对此客户端进行前端验证的标准检查。

Keycloak Web Gate

您可以使用 Laravel 授权 Gate 来检查用户是否具有一个或多个角色(和资源)。

例如,在您的控制器中,您可以检查 一个角色

if (Gate::denies('sso', 'manage-account')) {
  return abort(403);
}

或者 多个角色

if (Gate::denies('sso', ['manage-account'])) {
  return abort(403);
}

以及 资源的角色

if (Gate::denies('sso', 'manage-account', 'another-resource')) {
  return abort(403);
}

最后一种用法不简单,但您可以扩展保护器以请求多个资源的认证/授权。默认情况下,我们只请求当前客户端。

Keycloak 可中间件

如果您不想使用 Gate 或已实现的中间件,可以使用 sso-web-can 中间件来检查用户是否具有一个或多个角色。

将其添加到控制器的方法 __construct

$this->middleware('sso-web-can:manage-something-cool');

// For multiple roles, separate with '|'
$this->middleware('sso-web-can:manage-something-cool|manage-something-nice|manage-my-application');

此中间件在默认资源(client_id)上搜索所有角色。

您可以扩展它并在 Kernel.php 上注册自己的中间件,或者只需在控制器上使用 Auth::hasRole($roles, $resource)

常见问题解答

如何实现我的模型?

我们在 config/sso-web.php 中注册了一个名为 "sso-users" 的新用户提供程序。

在此相同的配置中,您设置了模型。因此,您可以注册自己的模型,扩展 Julidev\LaravelSsoKeycloak\Models\IAMUser 类并更改此配置。

您可以实现自己的 用户提供程序:只需记住实现 retrieveByCredentials 方法,该方法接收 Keycloak Profile 信息以检索模型的实例。

Eloquent/Database 用户提供程序应该运行良好,因为它们将解析 Keycloak Profile 并对您的数据库进行 "where" 查询。因此,您的用户数据必须与 Keycloak Profile 匹配。

我找不到我的登录表单。

我们注册了一个 login 路由以重定向到 Keycloak 服务器。登录后,我们将接收并处理令牌以验证您的用户。

没有登录/注册表单。

如何保护一个路由?

只需在默认中间件 auth 之前添加 sso 中间件。

// On RouteServiceProvider.php for example

Route::prefix('admin')
  ->middleware('sso')
  ->namespace($this->namespace)
  ->group(base_path('routes/web.php'));

// Or with Route facade in another place

Route::group(['middleware' => ['sso','web']], function () {
    Route::get('/admin', 'Controller@admin');
});

访问/刷新令牌和状态在哪里持久化?

在会话中。如果您有负载均衡,我们建议实现数据库驱动程序。

什么是状态?

状态是一个唯一且不可猜测的字符串,用于减轻 CSRF 攻击。

我们将即将发起的每个认证请求与一个随机状态关联,并在回调中检查。如果您正在扩展/实现自己的 Auth 控制器,则应执行此操作。

使用 IAMBadung::saveState() 方法将已生成的状态保存到会话中,并使用 IAMBadung::validateState() 检查当前状态是否与保存的状态匹配。

我在会话(卡在登录循环中)有问题。

由于某种原因,Laravel 可能会与 EncryptCookies 中间件更改会话 ID 的问题。

在这种情况下,我们总是会尝试登录,因为令牌无法检索。

您可以从加密中删除 session_id cookie。

// On your EncryptCookies middleware

class EncryptCookies extends Middleware
{
    protected $except = [];

    public function __construct(EncrypterContract $encrypter)
    {
        parent::__construct($encrypter);

        /**
         * This will disable in runtime.
         *
         * If you have a "session.cookie" option or don't care about changing the app name
         * (in another environment, for example), you can only add it to "$except" array on top
         */
        $this->disableFor(config('session.cookie'));
    }
}

我的客户端不是公开的。

如果您的客户端不是公开的,您应该在 .env 中提供 KEYCLOAK_CLIENT_SECRET

如何覆盖默认的 Guzzle 选项?

在某些用例中,您可能需要覆盖默认的 Guzzle 选项 - 可能是禁用 SSL 验证或将代理设置为将所有请求路由通过。

支持每个 Guzzle 请求选项,并将其直接传递给 Guzzle 客户端实例。

只需将您想要添加到 guzzle_options 数组的选项添加到 sso-web.php 配置文件中。例如

'guzzle_options' => [
    'verify' => false
]

特别感谢

GitHub 上的贡献者 ❤️