vivek-raghuvanshi/laravel-keycloak-guard

🔑 Laravel的简单Keycloak守卫

v1.0.1 2023-10-17 13:12 UTC

This package is auto-updated.

Last update: 2024-09-17 15:07:50 UTC


README

Laravel的简单Keycloak守卫

此软件包帮助您根据从Keycloak服务器生成的JWT令牌在Laravel API上对用户进行身份验证。

要求

✔️ 我正在使用Laravel构建API。

✔️ 我不会使用Laravel Passport进行身份验证,因为Keycloak服务器将完成这项工作。

✔️ 前端是一个独立的项目。

✔️ 前端用户将直接在Keycloak服务器上认证以获取JWT令牌。这个过程与Laravel API无关。

✔️ 前端将保留从Keycloak服务器获取的JWT令牌。

✔️ 前端使用该令牌向Laravel API发起请求。

流程

  1. 前端用户在Keycloak服务器上认证

  2. 前端用户获取JWT令牌。

  3. 在另一个时刻,前端用户使用该令牌向Laravel API上的受保护端点发起请求。

  4. Laravel API(通过Keycloak Guard)处理它。

    • 验证令牌签名。
    • 验证令牌结构。
    • 验证令牌过期时间。
    • 验证我的API是否允许从令牌访问资源
  5. 如果一切正常,则在数据库中找到用户并在我的API上对其进行身份验证。

  6. 可选地,用户可以在API用户数据库中创建/更新。

  7. 返回响应

安装

Lumen

需要此包

composer require vivek-raghuvanshi/laravel-keycloak-guard

Lumen专用

在您的bootstrap app文件 bootstrap/app.php 中注册提供者

在文件底部“注册服务提供者”部分添加以下行。

$app->register(\KeycloakGuard\KeycloakGuardServiceProvider::class);

对于外观,在您的bootstrap app文件 bootstrap/app.php 中取消注释 $app->withFacades();

配置

Keycloak Guard

⚠️ 在编辑 .env 时,请确保所有字符串都进行了修剪。

# Publish config file

php artisan vendor:publish  --provider="KeycloakGuard\KeycloakGuardServiceProvider"

✔️ realm_public_key

必需。

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

如何获取领域公钥?点击“领域设置”>“密钥”>“算法RS256”行>“公钥”按钮

✔️ load_user_from_database

必需。默认为true

如果您没有users表,您必须禁用此选项。

它从数据库中获取用户并将值填充到认证用户对象中。如果启用,它将与其他user_provider_credentialtoken_principal_attribute一起工作。

✔️ user_provider_custom_retrieve_method

默认为null

如果您有一个users表并且希望它根据令牌进行更新(创建或更新用户),则可以通知自定义UserProvider的自定义方法,该方法将在调用retrieveByCredentials而不是默认情况下接收完整的解码令牌作为参数。这将允许您自定义与数据库交互的方式,在匹配并交付认证用户对象之前,拥有所有包含在(有效)访问令牌中的信息。有关自定义UserProvider的更多信息,请参阅Laravel有关的文档。

如果使用此功能,显然,为user_provider_credentialtoken_principal_attribute定义的值将被忽略。

✔️ user_provider_credential

必需。默认为username

包含用户唯一标识符的“users”表字段(例如:用户名、电子邮件、昵称)。在认证过程中,它将与token_principal_attribute属性进行对比。

✔️ token_principal_attribute

必填项。默认值为 preferred_username

JWT令牌中包含用户标识的属性。在认证过程中,该属性将与user_provider_credential属性进行比对。

✔️ append_decoded_token

默认为 false

将完整的解码JWT令牌($user->token)附加到认证用户。如果您需要知道由JWT令牌持有的角色、组和其它用户信息,这将非常有用。即使选择false,您也可以使用Auth::token()来获取它,请参阅API部分。

✔️ allowed_resources

必填项.

通常您的API应该处理一个resource_access。但如果您处理多个,只需使用逗号分隔的受API接受的允许资源列表即可。在认证过程中,该属性将与JWT令牌中的resource_access属性进行比对。

✔️ ignore_resources_validation

默认为 false.

完全禁用资源验证。它将忽略allowed_resources配置。

✔️ leeway

默认为 0.

您可以为签名服务器和验证服务器之间可能存在的时钟偏差添加一些宽容时间。如果您遇到诸如"Cannot handle token prior to "等问题,请尝试将其设置为60(秒)。

✔️ input_key

默认为null

默认情况下,此包始终首先查找Bearer令牌。此外,如果启用此选项,则它将尝试从自定义请求参数中获取令牌。

// keycloak.php
'input_key' => 'api_token'

// If there is no Bearer token on request it will use `api_token` request param
GET  $this->get("/foo/secret?api_token=xxxxx")
POST $this->post("/foo/secret", ["api_token" => "xxxxx"])

Laravel认证

更改config/auth.php

...
'defaults' => [
        'guard' => 'api', # <-- For sure, i`m building an API
        'passwords' => 'users',
    ],

    ....

    'guards' => [
        # <!-----
        #     Make sure your "api" guard looks like this.
        #     Newer Laravel versions just removed this config block.
        #  ---->
        'api' => [
            'driver' => 'keycloak',
            'provider' => 'users',
        ],
    ],

Lumen路由

只需在routes/web.php中保护一些端点即可完成操作!

// public endpoints
$router->get('/hello', function () {
    return ':)';
});

// protected endpoints
$router->group(['middleware' => 'auth'], function () {
    $router->get('/protected-endpoint', 'SecretController@index');
    // more endpoints ...
});

API

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

默认Laravel方法

  • check()
  • guest()
  • user()
  • id()
  • validate()
  • setUser()
  • hasScope()
  • upsertUser()
  • getRoles()

Keycloak Guard方法

token() 返回认证用户的完整解码JWT令牌。

$token = Auth::token()  // or Auth::user()->token()

hasRole('some-resource', 'some-role') 检查认证用户在resource_access上是否有角色。

// Example decoded payload

'resource_access' => [
  'myapp-backend' => [
      'roles' => [
        'myapp-backend-role1',
        'myapp-backend-role2'
      ]
  ],
  'myapp-frontend' => [
    'roles' => [
      'myapp-frontend-role1',
      'myapp-frontend-role2'
    ]
  ]
]
Auth::hasRole('myapp-backend', 'myapp-backend-role1') // true
Auth::hasRole('myapp-frontend', 'myapp-frontend-role1') // true
Auth::hasRole('myapp-backend', 'myapp-frontend-role1') // false

hasAnyRole('some-resource', ['some-role1', 'some-role2']) 检查认证用户在resource_access上是否有任何角色。

Auth::hasAnyRole('myapp-backend', ['myapp-backend-role1', 'myapp-backend-role3']) // true
Auth::hasAnyRole('myapp-frontend', ['myapp-frontend-role1', 'myapp-frontend-role3']) // true
Auth::hasAnyRole('myapp-backend', ['myapp-frontend-role1', 'myapp-frontend-role2']) // false

贡献

您可以使用VSCODE的远程容器运行此项目。确保您将使用内部VSCODE终端(在运行容器内)。

composer install
composer test
composer test:coverage