gitlab-it / okta-sdk
Requires
- php: ^8.0 || ^8.1 || ^8.2
- illuminate/config: ^8.0 || ^9.0 || ^10.0
- illuminate/http: ^8.0 || ^9.0 || ^10.0
- illuminate/log: ^8.0 || ^9.0 || ^10.0
- illuminate/support: ^8.0 || ^9.0 || ^10.0
Requires (Dev)
- nunomaduro/larastan: ^1.0 || ^2.0
- orchestra/testbench: ^6.23 || ^7.0 || ^8.0
README
[[目录]]
概述
Okta SDK 是由 GitLab IT Engineering 开发的一个开源 Composer 包,用于在内部 Laravel 应用中连接到 Okta,以便进行用户、组、应用和其他相关功能的配置和取消配置。
免责声明:这不是 GitLab 或 Okta 产品和开发团队维护的官方包。这是我们 GitLab IT 部门内部使用的工具,我们将其开源作为公司价值观的一部分。
请在自己的风险下使用,并创建合并请求以解决您遇到的任何错误。
我们不为社区功能请求维护路线图,但我们邀请您贡献,我们很乐意审查您的合并请求。
v2 到 v3 升级指南
3.0 版本有几个重大更改。请参阅 v3.0 变更日志 了解更多信息。
更改内容
glamstack/okta-sdk
已被废弃,并重命名为gitlab-it/okta-sdk
。config/glamstack-gitlab.php
已重命名为config/gitlab-sdk.php
。没有进行数组更改。- 命名空间已从
Glamstack\Okta
更改为GitlabIt\Okta
。 - 从修改版的 Calendar Versioning (CalVer) 更改为使用 Semantic Versioning (SemVer)。
- 许可证已从
Apache 2.0
更改为MIT
。
迁移步骤
- 从
composer.json
中删除glamstack/okta-sdk
并添加"gitlab-it/okta-sdk": "^3.0"
,然后运行composer update
。 - 导航到您的
config
目录并将glamstack-okta.php
重命名为okta-sdk.php
。 - 在整个代码库中从
Glamstack\Okta
替换为GitlabIt\Okta
。 - 将
config('glamstack-okta.
替换为config('okta-sdk.
。
维护者
名称 | GitLab 处理 |
---|---|
Dillon Wheeler | @dillonwheeler |
Jeff Martin | @jeffersonmartin |
工作原理
您的 Okta 实例的 URL(例如 https://mycompany.okta.com
)和 API 令牌在 config/okta-sdk.php
中指定,使用从您的 .env
文件继承的变量。
如果您的连接配置存储在数据库中并需要动态提供,可以在初始化 SDK 期间通过传递数组到 connection_config
参数来覆盖 config/okta-sdk.php
配置文件。请参阅 按 API 调用动态变量连接 了解更多信息。
我们不是为 API 文档中的每个端点提供方法,而是采取了更简单的方法,提供了一个通用的 ApiClient
,它可以对您在 Okta API 文档 中找到的任何端点执行 GET
、POST
、PUT
和 DELETE
请求,并为您处理 API 响应、错误处理和分页。
此功能基于由Guzzle HTTP客户端(见Guzzle HTTP客户端提供)支持的Laravel HTTP客户端的简单性,为Okta API响应提供“代码解析的最后一步”,以改善开发者的体验。
以下示例是一个入门指南。有关详细信息,请参阅下面的API请求和API响应部分。
// Option 1. Initialize the SDK using the default connection
$okta_api = new \GitlabIt\Okta\ApiClient();
// Option 2. Initialize the SDK using a specific hard coded connection
$okta_api = new \GitlabIt\Okta\ApiClient('prod');
// Get a list of records
// https://developer.okta.com/docs/reference/api/groups/#list-groups
$groups = $okta_api->get('/groups');
// Search for records with a specific name
// https://developer.okta.com/docs/reference/core-okta-api/#filter
// https://developer.okta.com/docs/reference/api/groups/#list-groups-with-search
$groups = $okta_api->get('/groups', [
'search' => 'profile.name eq "Hack the Planet Engineers"'
]);
// https://developer.okta.com/docs/reference/api/users/#list-users-with-search
$users = $okta_api->get('/users', [
'search' => 'profile.firstName eq "Dade"'
]);
// Get a specific record
// https://developer.okta.com/docs/reference/api/groups/#get-group
$record = $okta_api->get('/groups/0oa1ab2c3D4E5F6G7h8i');
// Create a group
// https://developer.okta.com/docs/reference/api/groups/#add-group
$record = $okta_api->post('/groups', [
'profile' => [
'name' => 'Hack the Planet Engineers',
'description' => 'This group contains engineers that have proven they are elite enough to hack the Gibson.'
]
]);
// Update a group
// https://developer.okta.com/docs/reference/api/groups/#update-group
$group_id = '0oa1ab2c3D4E5F6G7h8i';
$record = $okta_api->put('/groups/' . $group_id, [
'profile' => [
'description' => 'This group contains engineers that have liberated the garbage files.'
]
]);
// Delete a group
// https://developer.okta.com/docs/reference/api/groups/#remove-group
$group_id = '0oa1ab2c3D4E5F6G7h8i';
$record = $okta_api->delete('/groups/' . $group_id);
安装
要求
要求 | 版本 |
---|---|
PHP | ^8.0 , ^8.1 , ^8.2 |
Laravel | ^8.0 , ^9.0 , ^10.0 |
添加Composer包
仍然使用
glamstack/okta-sdk
(v2.x)?请参阅v3.0升级指南以了解升级到gitlab-it/okta-sdk:^3.0
的说明。
composer require gitlab-it/okta-sdk:^3.0
如果您正在为此包做出贡献,请参阅CONTRIBUTING.md以获取配置具有符号链接的本地composer包的说明。
发布配置文件
此命令应仅在你首次使用此包时运行。如果你再次运行此命令,且未备份旧配置文件,则将覆盖任何自定义配置。
php artisan vendor:publish --tag=okta-sdk
环境配置
环境变量
要开始使用,请将以下变量添加到您的.env
文件中。您可以在文件中的任何位置添加这些变量,每行一个,或者添加到文件底部(任选)。
# .env
OKTA_DEFAULT_CONNECTION="dev"
OKTA_DEV_BASE_URL=""
OKTA_DEV_API_TOKEN=""
OKTA_PREVIEW_BASE_URL=""
OKTA_PREVIEW_API_TOKEN=""
OKTA_PROD_BASE_URL=""
OKTA_PROD_API_TOKEN=""
连接键
我们使用连接键(也称为实例键)的概念,它引用了config/okta-sdk.php
中的配置数组,允许您配置Base URL、API Token .env
变量名以及Okta API每个连接的日志通道,并为该连接提供一个唯一的名称。
每个连接都关联着不同的Base URL和API token。
我们已经预先配置了dev
、preview
和prod
键,以帮助您快速开始,无需对config/okta-sdk.php
文件进行任何修改。
# config/okta-sdk.php
'connections' => [
'prod' => [
'base_url' => env('OKTA_PROD_BASE_URL'),
'api_token' => env('OKTA_PROD_API_TOKEN'),
'log_channels' => ['single'],
],
'preview' => [
'base_url' => env('OKTA_PREVIEW_BASE_URL'),
'api_token' => env('OKTA_PREVIEW_API_TOKEN'),
'log_channels' => ['single'],
],
'dev' => [
'base_url' => env('OKTA_DEV_BASE_URL'),
'api_token' => env('OKTA_DEV_API_TOKEN'),
'log_channels' => ['single'],
],
]
如果您有很少见的用例,例如拥有额外的Okta实例或最低权限服务帐户,您可以在config/okta-sdk.php
中添加额外的连接键,使用您选择的名称,并使用其他连接作为示例创建新的Base URL和API token变量。
Base URL
每个Okta客户都为其公司提供一个子域。这有时被称为租户或API文档中的${yourOktaDomain}
。这应在prod
连接键中配置或使用.env
变量(见下文)。
https://mycompany.okta.com
如果您可以访问Okta的预览沙箱/测试/预发布实例,您也可以在preview
连接键中配置Base URL和API token。
https://mycompany.oktapreview.com
如果您有免费的Okta开发者帐户,您也可以在dev
键中配置Base URL和API token。
https://dev-12345678.okta.com
API Tokens
有关创建API token的说明,请参阅Okta文档。请注意,API token使用它所属用户的权限,因此对于生产应用程序用例,最好创建一个服务帐户(机器人)用户。任何30天内没有API调用的活动token将自动过期。
安全警告:请不要将您的API令牌添加到
config/okta-sdk.php
文件中,以避免将其提交到您的仓库(秘密泄露)。所有API令牌都应定义在.env
文件中,该文件包含在.gitignore
中,且不会提交到您的仓库。对于高级用例,您可以将变量存储在CI/CD变量或密钥库中(此处未提供文档)。
内部开发者说明:初始化SDK时,API密钥会自动以
SSWS
前缀。
默认全局连接
默认情况下,SDK将使用dev
连接密钥处理您应用程序中所有API调用,除非您使用OKTA_DEFAULT_CONNECTION
变量覆盖默认连接到不同的连接密钥。
如果您刚开始使用,建议保留此设置为dev
,以便您可以使用此SDK与您的Okta开发者账户一起使用。当您的应用程序部署到预发布或生产环境时,您可以稍后将其更改为preview
或prod
。
OKTA_DEFAULT_CONNECTION="dev"
默认连接密钥变量
您可以使用任何组合的prod
、preview
或dev
连接密钥。请确保将mycompany
替换为您自己的URL。
简单地保留任何未使用的连接为空,或从您的.env
文件中删除它们。您以后可以随时添加它们。
# .env
OKTA_DEFAULT_CONNECTION="dev"
OKTA_DEV_BASE_URL="https://dev-12345678.okta.com"
OKTA_DEV_API_TOKEN="YourDevT0k3nG0esH3r3"
OKTA_PREVIEW_BASE_URL="https://mycompany.oktapreview.com"
OKTA_PREVIEW_API_TOKEN="YourPreviewT0k3nG0esH3r3"
OKTA_PROD_BASE_URL="https://mycompany.okta.com"
OKTA_PROD_API_TOKEN="YourProdT0k3nG0esH3r3"
初始化API连接
要使用默认连接,您无需向ApiClient
提供connection key
。这允许您在不硬编码连接密钥的情况下构建应用程序,只需更新.env
变量即可。
// Initialize the SDK
$okta_api = new \GitlabIt\Okta\ApiClient();
// Get a list of records
// https://developer.okta.com/docs/reference/api/groups/#list-groups
$groups = $okta_api->get('/groups');
针对API调用使用特定的连接
如果您想使用与OKTA_DEFAULT_CONNECTION
.env
变量不同的特定connection key
时使用ApiClient
,可以将已在config/okta-sdk.php
中配置的任何connection key
作为ApiClient
的第一个构造参数传递。
// Initialize the SDK
$okta_api = new \GitlabIt\Okta\ApiClient('preview');
// Get a list of records
// https://developer.okta.com/docs/reference/api/groups/#list-groups
$groups = $okta_api->get('/groups');
如果您遇到错误,请确保API令牌已添加到您的
.env
文件中的OKTA_{CONNECTION_KEY}_API_TOKEN
变量中。请注意,Okta API令牌在30天不活跃后自动过期,因此您可能已经有一段时间没有运行dev
或preview
API调用,并收到未经授权的错误消息。
API调用时的动态变量连接
如果没有在config/okta-sdk.php
配置文件中使用连接密钥,可以将包含自定义连接配置的数组作为第二个参数传递。
// Initialize the SDK
$okta_api = new \GitlabIt\Okta\ApiClient(null, [
'base_url' => 'https://mycompany.okta.com',
'api_token' => '00fJq-ABCDEFGhijklmn0pQrsTu-Vw-xyZ12345678'
'log_channels' => ['single', 'okta-sdk']
]);
安全警告:不要将硬编码的API令牌提交到您的代码库。这仅在存储在您的数据库中的动态变量中使用。
以下是如何使用您自己的Eloquent模型存储您的Okta实例并将它们提供给SDK的示例。您可以选择是否提供动态日志通道作为应用程序逻辑的一部分,或者将您在应用程序中配置并使用SDK的通道硬编码。
// The $okta_instance_id is provided dynamically in the controller or service request
// Get Okta Instance
// Disclaimer: This is an example and is not a feature of the SDK.
$okta_instance = \App\Models\OktaInstance::query()
->where('id', $okta_instance_id)
->firstOrFail();
// Initialize the SDK
$okta_api = new \GitlabIt\Okta\ApiClient(null, [
'base_url' => $okta_instance->api_base_url,
'api_token' => decrypt($okta_instance->api_token),
'log_channels' => ['single', 'okta-sdk']
]);
日志配置
默认情况下,我们使用配置在您的应用程序的config/logging.php
文件中的single
通道处理所有日志。这会将所有Okta API日志消息发送到storage/logs/laravel.log
文件。
您可以在config/okta-sdk.php
中配置此SDK的日志通道。您还可以在auth.log_channels
中配置初始认证的日志通道。您还可以在connections.{connection_key}.log_channels
中为每个连接配置日志通道。
// config/okta-sdk.php
'auth' => [
'log_channels' => ['single'],
],
'connections' => [
'prod' => [
// ...
'log_channels' => ['single'],
],
'preview' => [
// ...
'log_channels' => ['single'],
],
'dev' => [
// ...
'log_channels' => ['single'],
],
]
自定义日志通道
如果您希望将Okta API日志存储在单独的日志文件中,以便更容易进行故障排除而不受无关日志消息的干扰,您可以创建一个自定义日志通道。例如,我们建议使用okta-sdk
的值,但您可以选择任何您喜欢的名称。您还可以为每个Okta连接创建一个日志通道(例如,okta-sdk-prod
和okta-sdk-preview
)。
将自定义日志通道添加到config/logging.php
文件。
// config/logging.php
'channels' => [
// Add anywhere in the `channels` array
'okta-sdk' => [
'name' => 'okta-sdk',
'driver' => 'single',
'level' => 'debug',
'path' => storage_path('logs/okta-sdk.log'),
],
],
更新channels.stack.channels
数组以包含自定义通道的数组键(例如,okta-sdk
)。请确保将okta-sdk
添加到现有数组值中,而不是替换现有值。
// config/logging.php
'channels' => [
'stack' => [
'driver' => 'stack',
'channels' => ['single','slack', 'okta-sdk'],
'ignore_exceptions' => false,
],
],
最后,更新config/okta-sdk.php
配置。
// config/okta-sdk.php
'auth' => [
'log_channels' => ['okta-sdk'],
],
您可以使用这些配置步骤重复自定义任何连接键。
安全最佳实践
不共享令牌
不要使用您已经为其他目的创建的API令牌。您应该为每个用例生成新的API令牌。
这在安全事件期间非常有用,当需要在一个受损害的系统上吊销密钥,并且您不希望使用相同用户或服务账户的其它系统受到影响,因为它们使用的是未被吊销的不同密钥。
API令牌存储
不要将您的API令牌添加到config/okta-sdk.php
文件中,以避免将其提交到您的存储库(秘密泄露)。
所有API令牌都应在.env
文件中定义,该文件包含在.gitignore
中,并且不会被提交到您的存储库。
建议将每个API令牌的副本存储在您首选的密码管理器(例如1Password、LastPass等)和/或秘密保险库(例如HashiCorp Vault、Ansible等)中。
API令牌权限
不同的Okta API操作需要不同的管理员权限级别。API令牌继承用于创建它们的管理员账户的权限级别。因此,创建一个用于创建API令牌的服务账户是一个好习惯,以便您可以分配所需的具体权限级别。有关管理员账户类型和每个账户的特定权限,请参阅管理员文档。
最小权限
如果您需要使用不同的API密钥以实现最小权限安全原因,您可以通过使用不同的连接键(例如prod_scope1
、prod_scope2
、prod_scope3
)将相同的Okta Base URL多次添加到config/okta-sdk.php
中来自定义它。
您可以根据需要自定义.env
变量名称。SDK使用来自config/okta-sdk.php
文件中的值,并不直接使用任何.env
变量。
'prod_read_only' => [
'base_url' => env('OKTA_PROD_BASE_URL'),
'api_token' => env('OKTA_PROD_READ_ONLY_API_TOKEN'),
'log_channels' => ['single']
],
'prod_super_admin' => [
'base_url' => env('OKTA_PROD_BASE_URL'),
'api_token' => env('OKTA_PROD_SUPER_ADMIN_API_TOKEN'),
'log_channels' => ['single']
],
'prod_group_admin' => [
'base_url' => env('OKTA_PROD_BASE_URL'),
'api_token' => env('OKTA_PROD_GROUP_ADMIN_API_TOKEN'),
'log_channels' => ['single']
],
您只需要在调用SDK时提供连接键。
$okta_api = new \GitlabIt\Okta\ApiClient('prod_read_only');
$groups = $okta_api->get('/groups')->object();
如果您需要更多灵活性,请使用按API调用动态变量连接。
API请求
您可以向Okta REST API文档中的任何资源端点发出API请求。
内联使用
// Initialize the SDK
$okta_api = new \GitlabIt\Okta\ApiClient('prod');
GET请求
端点在/api/v1
之后以/
开头。Okta API文档提供了完整的端点,因此在复制和粘贴端点时请删除/api/v1
。
以下示例请参考列出所有组API文档。
使用SDK时,您可以使用带有端点/groups
的get()
方法作为第一个参数。
$okta_api->get('/groups');
您还可以使用变量或数据库模型来获取构建端点所需的数据。
$endpoint = '/groups';
$records = $okta_api->get($endpoint);
以下是使用端点的更多示例。
// Get a list of records
// https://developer.okta.com/docs/reference/api/groups/#list-groups
$records = $okta_api->get('/groups');
// Get a specific record
// https://developer.okta.com/docs/reference/api/groups/#get-group
$record = $okta_api->get('/groups/0oa1ab2c3D4E5F6G7h8i');
// Get a specific record using a variable
// This assumes that you have a database column named `api_group_id` that
// contains the string with the Okta ID `0oa1ab2c3D4E5F6G7h8i`.
$okta_group = App\Models\OktaGroup::where('id', $id)->firstOrFail();
$api_group_id = $okta_group->api_group_id;
$record = $okta_api->get('/groups/' . $api_group_id);
带有查询字符串参数的GET请求
get()
方法的第二个参数是一个可选的参数数组,该数组由SDK和Laravel HTTP客户端解析,并以查询字符串的形式呈现,自动添加了?
和&
。
// Search for records with a specific name
// https://developer.okta.com/docs/reference/api/groups/#list-groups-with-search
$records = $okta_api->get('/groups', [
'search' => 'profile.name eq "Hack the Planet Engineers"'
]);
// This will parse the array and render the query string
// https://mycompany.okta.com/api/v1/groups?search=profile.name+eq+%22Hack%20the&%20Planet%20Engineers%22
// List all deprovisioned users
// https://developer.okta.com/docs/reference/api/users/#list-users-with-search
$records = $okta_api->get('/users', [
'search' => 'status eq "DEPROVISIONED"'
]);
// This will parse the array and render the query string
// https://mycompany.okta.com/api/v1/groups?search=status+eq+%22DEPROVISIONED%22
// Get all users for a specific department
// https://developer.okta.com/docs/reference/api/users/#list-users-with-search
$records = $okta_api->get('/users', [
'search' => 'profile.department eq "Engineering"'
]);
// This will parse the array and render the query string
// https://mycompany.okta.com/api/v1/groups?search=profile.department+eq+%22Engineering%22
POST请求
post()
方法几乎与get()
请求相同,都有一个参数数组,但是参数以application/json
内容类型作为表单数据传递,而不是作为查询字符串在URL中传递。这是行业标准,并不特定于SDK。
您可以在Laravel HTTP客户端文档中了解更多关于请求数据的信息。
// Create a group
// https://developer.okta.com/docs/reference/api/groups/#add-group
$record = $okta_api->post('/groups', [
'profile' => [
'name' => 'Hack the Planet Engineers',
'description' => 'This group contains engineers that have proven they are elite enough to hack the Gibson.'
]
]);
PUT请求
put()
方法用于更新现有记录(类似于PATCH
请求)。您需要确保在第一个参数(URI)中提供要更新的记录的ID。
在大多数应用程序中,这将是从您的数据库或其他位置获取的变量,而不是硬编码的。
// Update a group
// https://developer.okta.com/docs/reference/api/groups/#update-group
$group_id = '0oa1ab2c3D4E5F6G7h8i';
$record = $okta_api->put('/groups/' . $group_id, [
'profile' => [
'description' => 'This group contains engineers that have liberated the garbage files.'
]
]);
DELETE请求
delete()
方法用于基于您提供的ID销毁资源的操作。
请注意,delete()
方法将根据供应商返回不同的状态码(例如,200、201、202、204等)。Okta的API对于成功删除的资源将返回204
状态码。您应该使用$response->status->successful
布尔值来检查结果。
// Delete a group
// https://developer.okta.com/docs/reference/api/groups/#remove-group
$group_id = '0oa1ab2c3D4E5F6G7h8i';
$record = $okta_api->delete('/groups/' . $group_id);
类方法
上面的示例显示了适合大多数用例的基本内联使用。如果您喜欢使用类和构造函数,下面的示例将提供一个有用的示例。
<?php
use GitlabIt\Okta\ApiClient;
class OktaGroupService
{
protected $okta_api;
public function __construct($connection_key = null)
{
// If connection key is null, use the default connection key
if(! $connection_key) {
$connection_key = config('okta-sdk.auth.default_connection');
}
$this->$okta_api = new ApiClient($connection_key);
}
public function listGroups($query = [])
{
$groups = $this->$okta_api->get('/groups', $query);
return $groups->object;
}
public function getGroup($id, $query = [])
{
$group = $this->$okta_api->get('/groups/'.$id, $query);
return $group->object;
}
public function storeGroup($request_data)
{
$group = $this->$okta_api->post('/groups', $request_data);
// To return an object with the newly created group
return $group->object;
// To return the ID of the newly created group
// return $group->object->id;
// To return the status code of the form request
// return $group->status->code;
// To return a bool with the status of the form request
// return $group->status->successful;
// To throw an exception if the request fails
// throw_if(!$group->status->successful, new \Exception($group->error->message, $group->status->code));
// To return the entire API response with the object, json, headers, and status
// return $group;
}
public function updateGroup($id, $request_data)
{
$group = $this->$okta_api->put('/groups/'.$id, $request_data);
// To return an object with the updated group
return $group->object;
// To return a bool with the status of the form request
// return $group->status->successful;
}
public function deleteGroup($id)
{
$group = $this->$okta_api->delete('/groups/'.$id);
return $group->status->successful;
}
}
API响应
此SDK使用GitLab IT标准进行API响应格式化。
// API Request
$group = $okta_api->get('/groups/0oa1ab2c3D4E5F6G7h8i');
// API Response
$group->headers; // array
$group->json; // json
$group->object; // object
$group->status; // object
$group->status->code; // int (ex. 200)
$group->status->ok; // bool
$group->status->successful; // bool
$group->status->failed; // bool
$group->status->serverError; // bool
$group->status->clientError; // bool
API响应头
由于键使用连字符,与访问键值语法冲突,因此头作为数组返回,而不是对象。
$group = $okta_api->get('/groups/0oa1ab2c3D4E5F6G7h8i');
$group->headers;
[
"Date" => "Sun, 30 Jan 2022 01:11:44 GMT",
"Content-Type" => "application/json",
"Transfer-Encoding" => "chunked",
"Connection" => "keep-alive",
"Server" => "nginx",
"Public-Key-Pins-Report-Only" => "pin-sha256="REDACTED="; pin-sha256="REDACTED="; pin-sha256="REDACTED="; pin-sha256="REDACTED="; max-age=60; report-uri="https://okta.report-uri.com/r/default/hpkp/reportOnly"",
"Vary" => "Accept-Encoding",
"x-okta-request-id" => "A1b2C3D4e5@f6G7H8I9j0k1L2M3",
"x-xss-protection" => "0",
"p3p" => "CP="HONK"",
"x-rate-limit-limit" => "1000",
"x-rate-limit-remaining" => "998",
"x-rate-limit-reset" => "1643505155",
"cache-control" => "no-cache, no-store",
"pragma" => "no-cache",
"expires" => "0",
"content-security-policy" => "default-src 'self' mycompany.okta.com *.oktacdn.com; connect-src 'self' mycompany.okta.com mycompany-admin.okta.com *.oktacdn.com *.mixpanel.com *.mapbox.com app.pendo.io data.pendo.io pendo-static-5634101834153984.storage.googleapis.com mycompany.kerberos.okta.com https://oinmanager.okta.com data:; script-src 'unsafe-inline' 'unsafe-eval' 'self' mycompany.okta.com *.oktacdn.com; style-src 'unsafe-inline' 'self' mycompany.okta.com *.oktacdn.com app.pendo.io cdn.pendo.io pendo-static-5634101834153984.storage.googleapis.com; frame-src 'self' mycompany.okta.com mycompany-admin.okta.com login.okta.com; img-src 'self' mycompany.okta.com *.oktacdn.com *.tiles.mapbox.com *.mapbox.com app.pendo.io data.pendo.io cdn.pendo.io pendo-static-5634101834153984.storage.googleapis.com data: blob:; font-src 'self' mycompany.okta.com data: *.oktacdn.com fonts.gstatic.com",
"expect-ct" => "report-uri="https://oktaexpectct.report-uri.com/r/t/ct/reportOnly", max-age=0",
"x-content-type-options" => "nosniff",
"Strict-Transport-Security" => "max-age=315360000; includeSubDomains",
"set-cookie" => "sid=""; Expires=Thu, 01-Jan-1970 00:00:10 GMT; Path=/ autolaunch_triggered=""; Expires=Thu, 01-Jan-1970 00:00:10 GMT; Path=/ JSESSIONID=E07ED763D2ADBB01B387772B9FB46EBF; Path=/; Secure; HttpOnly"
]
API响应特定头
$content_type = $group->headers['Content-Type'];
application/json
API响应JSON
$group = $okta_api->get('/groups/0oa1ab2c3D4E5F6G7h8i');
$group->json;
"{"id":0oa1ab2c3D4E5F6G7h8i,"name":"Hack the Planet Engineers","state":"ACTIVE"}"
API响应对象
$group = $okta_api->get('/groups/0oa1ab2c3D4E5F6G7h8i');
$group->object;
{
+"id": "0oa1ab2c3D4E5F6G7h8i"
+"description": "This group contains engineers that have proven they are elite enough to hack the Gibson."
+"name": "Hack the Planet Engineers"
+"state": "ACTIVE"
}
访问单个记录值
您可以使用对象符号访问这些变量。这是处理API响应的最常见用例。
$group = $okta_api->get('/groups/0oa1ab2c3D4E5F6G7h8i')->object;
dd($group->name);
Hack the Planet Engineers
遍历记录
如果您有一组多个对象,您可以遍历记录。
$groups = $okta_api->get('/groups')->object;
foreach($groups as $group) {
dd($group->name);
}
Hack the Planet Engineers
缓存响应
SDK不使用缓存,以避免您无法控制要缓存的端点。
在调用API时,您可以在端点周围包装缓存外观。您可以在Laravel缓存文档中了解更多信息。
use Illuminate\Support\Facades\Cache;
$okta_api = new \GitlabIt\Okta\ApiClient($connection_key);
$groups = Cache::remember('okta_groups', now()->addHours(12), function () use ($okta_api) {
return $okta_api->get('/groups')->object;
});
foreach($groups as $group) {
dd($group->name);
}
当获取特定ID或传递其他参数时,请确保在use($var1, $var2)
中传递变量。
$okta_api = new \GitlabIt\Okta\ApiClient($connection_key);
$group_id = '0oa1ab2c3D4E5F6G7h8i';
$groups = Cache::remember('okta_group_' . $group_id, now()->addHours(12), function () use ($okta_api, $group_id) {
return $okta_api->get('/groups/' . $group_id)->object;
});
API响应状态
请参阅Laravel HTTP客户端文档以了解有关不同状态布尔值的更多信息。
$group = $okta_api->get('/groups/0oa1ab2c3D4E5F6G7h8i');
$group->status;
{
+"code": 200
+"ok": true
+"successful": true
+"failed": false
+"serverError": false
+"clientError": false
}
API响应状态码
$group = $okta_api->get('/groups/0oa1ab2c3D4E5F6G7h8i');
$group->status->code;
200
错误处理
所有Okta API响应都会从SDK返回到您的应用程序,如果没有错误则不会抛出异常。如果您需要检查成功的结果,请使用$response->status->successful
布尔值。
Okta错误码
如果请求不成功,将返回标准的Okta错误码响应。
+"object": {#1344
+"errorCode": "E0000003"
+"errorSummary": "The request body was not well-formed."
+"errorLink": "E0000003"
+"errorId": "<string>"
+"errorCauses": []
}
+"status": {#1369
+"code": 400
+"ok": false
+"successful": false
+"failed": true
+"serverError": false
+"clientError": true
}
捕获状态码
$group = $this->$okta_api->post('/groups', $request_data);
您可以使用表单请求的状态返回布尔值或HTTP状态码。请参阅API响应状态以了解您可以返回的其他属性。
return $group->status->successful;
return $group->status->code;
您还可以在应用程序中使用\Exception
或自定义异常抛出异常。
throw_if(!$group->status->successful, new \Exception($group->error->message, $group->status->code));
您还可以使用条件语句来处理成功和失败响应。
if($group->status->successful) {
dd('Group Saved - ID ' . $group->object->id);
} else {
dd('Group Could Not Be Saved - Reason: ' . $group->object->errorSummary);
}
如果Guzzle抛出\Illuminate\Http\Client\RequestException
异常,则不会返回object
和json
属性,并将包含有关异常的更多详细信息的错误对象包含在内,以便您可以优雅地处理错误。
{
+"error": {
+"code": "<string>"
+"message": "<string>"
+"reference": "<string>"
}
+"status": {
+"code": 400
+"ok": false
+"successful": false
+"failed": true
+"serverError": false
+"clientError": true
}
如果SDK配置或认证出错,将抛出带有错误消息的新\Exception
。
请参阅下面的日志输出,了解SDK如何处理配置错误。
请参阅Okta API错误代码文档,了解可以返回的代码。有关每个资源端点的更多信息,可以在相应的API文档页面找到。
日志输出
错误消息的输出显示在
README
中,以便搜索引擎可以索引这些消息以支持开发者的调试。
连接配置和认证
首次调用ApiClient
类时,将对Okta连接的/org
端点执行API连接测试。此端点需要认证,因此这验证了API令牌是否有效。
$okta_api = new \GitlabIt\Okta\ApiClient('prod');
$okta_api->get('/groups');
有效的API令牌
[2022-01-31 23:38:56] local.INFO: GET 200 https://gitlab.okta.com/api/v1/org {"api_endpoint":"https://gitlab.okta.com/api/v1/org","api_method":"GET","class":"GitlabIt\\Okta\\ApiClient","connection_key":"prod","message":"GET 200 https://gitlab.okta.com/api/v1/org","event_type":"okta-api-response-info","okta_request_id":"YfhzENHYyWivKath4UvZhAAAAt8","rate_limit_remaining":"998","status_code":200}
[2022-01-31 23:38:56] local.INFO: GET 200 https://gitlab.okta.com/api/v1/groups {"api_endpoint":"https://gitlab.okta.com/api/v1/groups","api_method":"GET","class":"GitlabIt\\Okta\\ApiClient","connection_key":"prod","message":"GET 200 https://gitlab.okta.com/api/v1/groups","event_type":"okta-api-response-info","okta_request_id":"YfhzEC100RhpyNJdV3sEiAAABmQ","rate_limit_remaining":"499","status_code":200}
缺少API令牌
[2022-01-31 23:40:26] local.CRITICAL: The API token for this Okta connection key is not defined in your `.env` file. The variable name for the API token can be found in the connection configuration in `config/okta-sdk.php`. Without this API token, you will not be able to performed authenticated API calls. {"event_type":"okta-api-config-missing-error","class":"GitlabIt\\Okta\\ApiClient","status_code":"501","message":"The API token for this Okta connection key is not defined in your `.env` file. The variable name for the API token can be found in the connection configuration in `config/okta-sdk.php`. Without this API token, you will not be able to performed authenticated API calls.","connection_key":"prod"}
无效的API令牌
[2022-01-31 23:41:01] local.NOTICE: GET 401 https://gitlab.okta.com/api/v1/org {"api_endpoint":"https://gitlab.okta.com/api/v1/org","api_method":"GET","class":"GitlabIt\\Okta\\ApiClient","connection_key":"prod","event_type":"okta-api-response-client-error","message":"GET 401 https://gitlab.okta.com/api/v1/org","okta_request_id":"Yfhzjforta34Ho5ON3SqeQAADlY","okta_error_causes":[],"okta_error_code":"E0000011","okta_error_id":"oaepVpdl1ZQQO-U7Ki-e_-wHQ","okta_error_link":"E0000011","okta_error_summary":"Invalid token provided","rate_limit_remaining":null,"status_code":401}
ApiClient构造API令牌
$okta_api = new \GitlabIt\Okta\ApiClient('prod', '00fJq-A1b2C3d4E5f6G7h8I9J0-Kl-mNoPqRsTuVwx');
$okta_api->get('/groups');
[2022-01-31 23:42:04] local.NOTICE: The Okta API token for these API calls is using an API token that was provided in the ApiClient construct method. The API token that might be configured in the `.env` file is not being used. {"event_type":"okta-api-config-override-notice","class":"GitlabIt\\Okta\\ApiClient","status_code":"203","message":"The Okta API token for these API calls is using an API token that was provided in the ApiClient construct method. The API token that might be configured in the `.env` file is not being used.","okta_connection":"prod"}
[2022-01-31 23:42:04] local.INFO: GET 200 https://gitlab.okta.com/api/v1/org {"api_endpoint":"https://gitlab.okta.com/api/v1/org","api_method":"GET","class":"GitlabIt\\Okta\\ApiClient","connection_key":"prod","message":"GET 200 https://gitlab.okta.com/api/v1/org","event_type":"okta-api-response-info","okta_request_id":"YfhzzDq5PIe70D1-C8HRHwAACdg","rate_limit_remaining":"999","status_code":200}
[2022-01-31 23:42:05] local.INFO: GET 200 https://gitlab.okta.com/api/v1/groups {"api_endpoint":"https://gitlab.okta.com/api/v1/groups","api_method":"GET","class":"GitlabIt\\Okta\\ApiClient","connection_key":"prod","message":"GET 200 https://gitlab.okta.com/api/v1/groups","event_type":"okta-api-response-info","okta_request_id":"YfhzzK6LrJwm1XbvpcPnGwAAA6g","rate_limit_remaining":"499","status_code":200}
缺少连接配置
[2022-01-31 23:43:03] local.CRITICAL: The Okta connection key is not defined in `config/okta-sdk.php` connections array. Without this array config, there is no URL or API token to connect with. {"event_type":"okta-api-config-missing-error","class":"GitlabIt\\Okta\\ApiClient","status_code":"501","message":"The Okta connection key is not defined in `config/okta-sdk.php` connections array. Without this array config, there is no URL or API token to connect with.","connection_key":"test"}
缺少基本URL
[2022-01-31 23:44:04] local.CRITICAL: The Base URL for this Okta connection key is not defined in `config/okta-sdk.php` or `.env` file. Without this configuration (ex. `https://mycompany.okta.com`), there is no URL to perform API calls with. {"event_type":"okta-api-config-missing-error","class":"GitlabIt\\Okta\\ApiClient","status_code":"501","message":"The Base URL for this Okta connection key is not defined in `config/okta-sdk.php` or `.env` file. Without this configuration (ex. `https://mycompany.okta.com`), there is no URL to perform API calls with.","connection_key":"test"}
速率限制
大多数速率限制是由于具有大响应的分页(例如,/users
端点)而触发的。如果您有大量数据集,您可能需要考虑使用search
查询来过滤结果以减少结果数量。
如果Okta端点的速率限制超出限制,将抛出带有消息Okta API速率限制超出
的新\Exception
。当剩余10%的速率限制时,日志将显示关于速率限制的警告。
大多数速率限制是每分钟一次,因此您可能需要在代码中添加sleep(#)
以减慢请求速度,或者考虑使用更有效的方法来发送API请求。某些端点允许您设置自定义每页limit
值。最大值可以在端点的Okta API文档中找到(取决于端点)。
[2023-02-26 18:04:18] local.INFO: GET 200 https://dev-12345678.okta.com/api/v1/groups {"api_endpoint":"https://dev-12345678.okta.com/api/v1/groups","api_method":"GET","class":"GitlabIt\\Okta\\ApiClient","connection_key":"dev","message":"GET 200 https://dev-12345678.okta.com/api/v1/groups","event_type":"okta-api-response-info","okta_request_id":"<string>","rate_limit_remaining":"5","status_code":200}
[2023-02-26 18:04:18] local.WARNING: 10 percent of Okta API rate limit remaining {"api_endpoint":"https://dev-12345678.okta.com/api/v1/groups","api_method":"GET","class":"GitlabIt\\Okta\\ApiClient","connection_key":"dev","event_type":"okta-api-rate-limit-approaching","message":"10 percent of Okta API rate limit remaining","okta_request_id":"<string>","okta_rate_limit_remaining":"5","okta_rate_limit_limit":"50","okta_rate_limit_percent":10.0,"status_code":200}
[2023-02-26 18:04:18] local.INFO: GET 200 https://dev-12345678.okta.com/api/v1/groups {"api_endpoint":"https://dev-12345678.okta.com/api/v1/groups","api_method":"GET","class":"GitlabIt\\Okta\\ApiClient","connection_key":"dev","message":"GET 200 https://dev-12345678.okta.com/api/v1/groups","event_type":"okta-api-response-info","okta_request_id":"<string>","rate_limit_remaining":"4","status_code":200}
[2023-02-26 18:04:18] local.WARNING: 8 percent of Okta API rate limit remaining {"api_endpoint":"https://dev-12345678.okta.com/api/v1/groups","api_method":"GET","class":"GitlabIt\\Okta\\ApiClient","connection_key":"dev","event_type":"okta-api-rate-limit-approaching","message":"8 percent of Okta API rate limit remaining","okta_request_id":"<string>","okta_rate_limit_remaining":"4","okta_rate_limit_limit":"50","okta_rate_limit_percent":8.0,"status_code":200}
[2023-02-26 18:04:19] local.INFO: GET 200 https://dev-12345678.okta.com/api/v1/groups {"api_endpoint":"https://dev-12345678.okta.com/api/v1/groups","api_method":"GET","class":"GitlabIt\\Okta\\ApiClient","connection_key":"dev","message":"GET 200 https://dev-12345678.okta.com/api/v1/groups","event_type":"okta-api-response-info","okta_request_id":"<string>","rate_limit_remaining":"3","status_code":200}
[2023-02-26 18:04:19] local.WARNING: 6 percent of Okta API rate limit remaining {"api_endpoint":"https://dev-12345678.okta.com/api/v1/groups","api_method":"GET","class":"GitlabIt\\Okta\\ApiClient","connection_key":"dev","event_type":"okta-api-rate-limit-approaching","message":"6 percent of Okta API rate limit remaining","okta_request_id":"<string>","okta_rate_limit_remaining":"3","okta_rate_limit_limit":"50","okta_rate_limit_percent":6.0,"status_code":200}
[2023-02-26 18:04:19] local.INFO: GET 200 https://dev-12345678.okta.com/api/v1/groups {"api_endpoint":"https://dev-12345678.okta.com/api/v1/groups","api_method":"GET","class":"GitlabIt\\Okta\\ApiClient","connection_key":"dev","message":"GET 200 https://dev-12345678.okta.com/api/v1/groups","event_type":"okta-api-response-info","okta_request_id":"<string>","rate_limit_remaining":"2","status_code":200}
[2023-02-26 18:04:19] local.WARNING: 4 percent of Okta API rate limit remaining {"api_endpoint":"https://dev-12345678.okta.com/api/v1/groups","api_method":"GET","class":"GitlabIt\\Okta\\ApiClient","connection_key":"dev","event_type":"okta-api-rate-limit-approaching","message":"4 percent of Okta API rate limit remaining","okta_request_id":"<string>","okta_rate_limit_remaining":"2","okta_rate_limit_limit":"50","okta_rate_limit_percent":4.0,"status_code":200}
[2023-02-26 18:04:20] local.INFO: GET 200 https://dev-12345678.okta.com/api/v1/groups {"api_endpoint":"https://dev-12345678.okta.com/api/v1/groups","api_method":"GET","class":"GitlabIt\\Okta\\ApiClient","connection_key":"dev","message":"GET 200 https://dev-12345678.okta.com/api/v1/groups","event_type":"okta-api-response-info","okta_request_id":"<string>","rate_limit_remaining":"1","status_code":200}
[2023-02-26 18:04:20] local.WARNING: 2 percent of Okta API rate limit remaining {"api_endpoint":"https://dev-12345678.okta.com/api/v1/groups","api_method":"GET","class":"GitlabIt\\Okta\\ApiClient","connection_key":"dev","event_type":"okta-api-rate-limit-approaching","message":"2 percent of Okta API rate limit remaining","okta_request_id":"<string>","okta_rate_limit_remaining":"1","okta_rate_limit_limit":"50","okta_rate_limit_percent":2.0,"status_code":200}
[2023-02-26 18:04:20] local.ERROR: Okta API rate limit exceeded {"event_type":"okta-api-rate-limit-exceeded","class":"GitlabIt\\Okta\\ApiClient","status_code":200,"message":"Okta API rate limit exceeded","api_method":"GET","api_endpoint":"https://dev-12345678.okta.com/api/v1/groups","connection_key":"dev","okta_request_id":"<string>","okta_rate_limit_remaining":"1","okta_rate_limit_limit":"50"}
在示例中,异常是在最后一个日志条目Okta API速率限制超出
时抛出的。
问题跟踪和错误报告
免责声明:这不是 GitLab 或 Okta 产品和开发团队维护的官方包。这是我们 GitLab IT 部门内部使用的工具,我们将其开源作为公司价值观的一部分。
请在自己的风险下使用,并创建合并请求以解决您遇到的任何错误。
我们不为社区功能请求维护路线图,但我们邀请您贡献,我们很乐意审查您的合并请求。
对于GitLab团队成员,请在gitlab-it/okta-sdk(公开)或gitlab-com/it/dev/issue-tracker(机密)中创建问题。
贡献
有关如何贡献的更多信息,请参阅CONTRIBUTING.md。