multitech-osp/laravel-keycloak

Laravel Keycloak for laravel

v1.2.4 2024-09-19 15:18 UTC

README

此库提供了 Laravel 和 Keycloak 之间的集成,用于处理身份验证和授权。

更新指南

从 v1.1.0 升级到 v1.2.0

在配置文件(config/keycloak.php)中,前缀不再是数组,从现在起它是一个字符串。

  • 您需要将 roles.prefixes 键的名称更改为 roles.prefix

安装

要安装此库,请使用 Composer

composer require multitech-osp/laravel-keycloak

添加服务提供者

安装包后,在 config/app.php 中添加服务提供者

'providers' => [
    ...
    \MultitechOsp\LaravelKeycloak\LaravelKeycloakServiceProvider::class
],

发布配置

安装包后,使用以下 Artisan 命令发布配置文件

php artisan vendor:publish --provider="MultitechOsp\LaravelKeycloak\LaravelKeycloakServiceProvider"

配置

发布后,配置文件将位于 config/keycloak.php。您可以在该文件中设置必要的 Keycloak 参数,或者直接在 .env 文件中设置。

.env 文件中配置设置示例

KEYCLOAK_URL=http://your-keycloak-url
KEYCLOAK_REALM=your-realm
KEYCLOAK_SCOPE=openid
KEYCLOAK_CLIENT_ID=your-client-id
KEYCLOAK_LOAD_MODEL=false
KEYCLOAK_MODEL_ID=id

配置文件示例

return [
    'url' => env('KEYCLOAK_URL'),
    'realm' => env('KEYCLOAK_REALM'),
    'scope' => env('KEYCLOAK_SCOPE', 'openid'),
    'client_id' => env('KEYCLOAK_CLIENT_ID', 'auth'),

    'model_load' => env('KEYCLOAK_LOAD_MODEL', false),
    'model_id' => env('KEYCLOAK_MODEL_ID', 'id'),

     'roles' => [
        'prefix' => env('KEYCLOAK_ROLES_PREFIX', 'sac'),
        'admin' => env('KEYCLOAK_ROLES_ADMIN', 'admin'),
        'permissions' => [
            'route_name' => [
                'keycloak_role_permission'
            ]
        ],
        'ignore_routes' => [
            'route_name'
        ]
    ],

    'routes' => [
        'prefix' => env('KEYCLOAK_ROUTE_PREFIX', 'api/v1'),
        'middleware' => env('KEYCLOAK_ROUTE_MIDDLEWARE', 'auth:api'),
    ],

    'manage' => [
        'client_id' => env('KEYCLOAK_MANAGE_CLIENT_ID', 'admin-cli'),
        'username' => env('KEYCLOAK_MANAGE_USERNAME', 'admin-realm'),
        'password' => env('KEYCLOAK_MANAGE_PASSWORD'),
        'subgroups_uuid' => [
            'admin' => env('KEYCLOAK_MANAGE_SUBGROUPS_ADMIN'),
            'view' => env('KEYCLOAK_MANAGE_SUBGROUPS_VIEW'),
        ]
    ],
];

设置守卫

要使用 Keycloak 守卫,您需要在位于 config 目录中的 config/auth.php 配置文件中进行配置

'guards' => [
    ...,

    'api' => [
        'driver' => 'keycloak',
        'provider' => 'users',
    ],
],

中间件

将发布 keycloak-role 中间件,并应使用它来使用 Keycloak 验证权限。

使用示例

Route::middleware('keycloak-role:api')
      ->apiResource('products', 'ProductController', ['except' => ['delete']]);

配置

要配置路由权限,请使用 config\keycloak.php 文件。它具有以下结构

'roles' => [
    'prefix' => env('KEYCLOAK_ROLES_PREFIX', 'sac'),
    'admin' => env('KEYCLOAK_ROLES_ADMIN', 'admin'),
    'permissions' => [
        'route_name' => [
            'keycloak_role_permission'
        ]
    ],
    'ignore_routes' => [
        'route_name'
    ]
],

参数描述

  • roles.prefix: 权限前缀。
  • roles.admin: 具有一般管理员访问应用程序的权限的权限名称。
  • roles.permissions: 包含具有访问权限的路线名称和权限名称的数组。数组的索引是路线名称,其值是一个包含可以访问它的 Keycloak 权限的数组。

权限示例

库将使用路线名称,将 "." 替换为 "-" 并添加前缀。例如:将 products.show 替换为 sac:products-show

如果权限不遵循此模式,必须在权限数组中定义它

'permissions' => [
    'products.show' => [
        'sac-admin:products-show'
    ]
]
  • roles.ignore_routes: 不需要权限即可访问的路线名称的数组。

可用方法

MultitechOsp\LaravelKeycloak\KeycloakService.php

public function login(string $username = '', string $password = ''): array;
public function logout(string $accessToken, string $refreshToken): bool;
public function refreshToken(string $refreshToken): array;
public function user(string $accessToken): array;

命令

keycloak:sync-permissions 命令将根据 keycloak-role 中间件具有的路线同步权限

php artisan keyclock:sync-permissions

路由

POST config('keycloak.routes.prefix')/auth/login
正文

{
    "username": "admin",
    "password": "admin"
}

POST config('keycloak.routes.prefix')/auth/logout
头部: Authorization Bearer {access_token}
正文

{
    "refresh_token": "your refresh token"
}

POST config('keycloak.routes.prefix')/auth/refresh
正文

{
    "refresh_token": "your refresh token"
}

GET config('keycloak.routes.prefix')/auth/verify/token
头部: Authorization Bearer {access_token}

Swagger-PHP

如果您需要 Swagger 文档,请参阅下面的代码快捷方式。

    /**
     * @OA\Post(
     *     path="/api/v1/auth/login",
     *     tags={"Auth"},
     *     summary="Auth login",
     *     operationId="auth.login",
     *     @OA\RequestBody(
     *          @OA\MediaType(
     *              mediaType="application/json",
     *              @OA\Schema(
     *                   @OA\Property(
     *                      property="username",
     *                      type="string",
     *                      example="admin",
     *                      description="Username or email"
     *                  ),
     *                   @OA\Property(
     *                      property="password",
     *                      type="string",
     *                      description="Password"
     *                  ),
     *              ),
     *         )
     *     ),
     *
     *     @OA\Response(
     *          response=200,
     *          description="successful operation",
     *          @OA\MediaType(
     *              mediaType="application/json",
     *              @OA\Schema(
     *                   @OA\Property(property="token",
     *                      type="string",
     *                      example="eyJ0eXAiOiJKV1QiLCJhbG...",
     *                      description="Token"
     *                  ),
     *                  @OA\Property(property="token_type",
     *                      type="string",
     *                      example="Bearer ",
     *                      description="Token type"
     *                  ),
     *                  @OA\Property(property="expires_in",
     *                      type="string",
     *                      example="2020-02-01 12:22:22",
     *                      description="expires_in"
     *                  ),
     *              ),
     *          ),
     *      ),
     *      @OA\Response(
     *         response=422,
     *         description="Validation"
     *      ),
     *      @OA\Response(
     *         response=400,
     *         description="The given data was invalid"
     *      ),
     * )
     */
    /**
     * @OA\Post(
     *     path="/api/v1/auth/refresh",
     *     tags={"Auth"},
     *     summary="Auth refresh",
     *     operationId="auth.refresh",
     *     @OA\RequestBody(
     *          @OA\MediaType(
     *              mediaType="application/json",
     *              @OA\Schema(
     *                   @OA\Property(
     *                      property="refresh_token",
     *                      type="string",
     *                      example="eyJhbGciOiJIUzI1NiI...",
     *                      description="Refresh token"
     *                  ),
     *              ),
     *         )
     *     ),
     *     @OA\Response(
     *          response=200,
     *          description="successful operation",
     *          @OA\MediaType(
     *              mediaType="application/json",
     *              @OA\Schema(
     *                   @OA\Property(
     *                      property="refresh_token",
     *                      type="string",
     *                      example="eyJhbGciOiJIUzI1NiI...",
     *                      description="Refresh token"
     *                  ),
     *              ),
     *          ),
     *      ),
     *      @OA\Response(
     *         response=422,
     *         description="Validation"
     *      ),
     *      @OA\Response(
     *         response=400,
     *         description="The given data was invalid"
     *      ),
     * )
     */
    /**
     * @OA\Post(
     *     path="/api/v1/auth/logout",
     *     tags={"Auth"},
     *     summary="Auth logout",
     *     operationId="auth.logout",
     *     security={{"token":{}}},
     *     @OA\RequestBody(
     *          @OA\MediaType(
     *              mediaType="application/json",
     *              @OA\Schema(
     *                   @OA\Property(
     *                      property="refresh_token",
     *                      type="string",
     *                      example="eyJhbGciOiJIUzI1NiI...",
     *                      description="Refresh token"
     *                  ),
     *              ),
     *         )
     *     ),
     *      @OA\Response(
     *          response=200,
     *          description="successful operation",
     *          @OA\MediaType(
     *              mediaType="application/json",
     *              @OA\Schema(
     *                   @OA\Property(
     *                      property="boolean",
     *                      type="boolean",
     *                      example="true",
     *                      description="If invalidation token return true"
     *                  ),
     *              ),
     *          ),
     *      ),
     *      @OA\Response(
     *         response=400,
     *         description="The given data was invalid"
     *      ),
     * )
     */
    /**
     * @OA\Get(
     *     path="/api/v1/auth/verify-token",
     *     tags={"Auth"},
     *     summary="Auth verify-token",
     *     operationId="auth.verify-token",
     *     security={{"token":{}}},
     *     @OA\RequestBody(
     *          @OA\MediaType(
     *              mediaType="application/json",
     *         )
     *     ),
     *      @OA\Response(
     *          response=200,
     *          description="successful operation",
     *
     *          @OA\MediaType(
     *              mediaType="application/json",
     *          ),
     *      ),
     *      @OA\Response(
     *         response=400,
     *         description="The given data was invalid"
     *      ),
     * )
     */

在 Packagist 中发布库的新版本

只需创建一个新的标签,它将自动可用

许可证

此库是开源软件,根据 MIT 许可证 许可。

贡献

欢迎贡献!请提交一个拉取请求或打开一个问题来讨论潜在的变化。

支持

对于支持,请在此存储库中打开一个问题。

此 README 提供了关于如何安装、配置和使用 Laravel Keycloak 集成库的概述。请确保用您的实际 Keycloak 设置替换占位符值。