首页 > 解决方案 > 如何通过 API 集成 keycloak 短信认证?

问题描述

我有一个使用自定义 KeycloakProvider 的 keycloak 服务器和 Laravel 应用程序:

public function loginByEmail(string $email, string $password): SsoTokens
{
    try {
        $data = $this->realmEndpoint->makeRequest(
            HttpClientProvider::METHOD_POST,
            self::KEYCLOAK_AUTH_URL,
            [
                'client_id' => config('services.keycloak.realm_client'),
                'client_secret' => config('services.keycloak.realm_secret'),
                'grant_type' => 'password',
                'username' => $email,
                'password' => $password,
                'scope' => 'openid'
            ]
        );
    } catch (TransportUnauthorizedException $e) {
        throw new UnauthorizedException($e);
    } catch (HttpClientException $e) {
        throw new TransportException($e);
    }

    return $this->extractTokens($data);
}

现在我的目标是通过用户的手机号码设置基本的短信认证。我找到了一些工具(12),但它们不提供 API,只提供 HTML 页面。有解决办法吗?

标签: keycloakkeycloak-rest-api

解决方案


我找到了解决方案。在不知道某人密码的情况下登录:

  1. 发简讯;
  2. 通过代码确认电话号码;
  3. 获取目标用户的keycloak ID;
  4. 以具有冒充权限的用户身份登录;
  5. 与目标用户交换代币。

TOKEN_EXCHANGE需要keycloak功能。

步骤 1-3 我使用 Laravel 实现,步骤 4-5 使用 Keycloak API:

public function loginByUserId(string $userId): SsoTokens
    {
        try {
            $impersonatorData = $this->realmEndpoint->makeRequest(
                HttpClientProvider::METHOD_POST,
                self::KEYCLOAK_AUTH_URL,
                [
                    'client_id' => config('services.keycloak.realm_client'),
                    'client_secret' => config('services.keycloak.realm_secret'),
                    'grant_type' => 'password',
                    'username' => config('services.keycloak.admin_username'),
                    'password' => config('services.keycloak.admin_password'),
                    'scope' => 'openid',
                ]
            );

            $data = $this->realmEndpoint->makeRequest(
                HttpClientProvider::METHOD_POST,
                self::KEYCLOAK_AUTH_URL,
                [
                    'client_id' => config('services.keycloak.realm_client'),
                    'client_secret' => config('services.keycloak.realm_secret'),
                    'grant_type' => 'urn:ietf:params:oauth:grant-type:token-exchange',
                    'requested_subject' => $userId,
                    'subject_token' => $impersonatorData['access_token'],
                    'scope' => 'openid',
                ]
            );
        } catch (TransportUnauthorizedException $e) {
            throw new UnauthorizedException($e);
        } catch (HttpClientException $e) {
            throw new TransportException($e);
        }

        return $this->extractTokens($data);
    }

推荐阅读