glamstack / okta-sdk
Requires
- php: ^8.0 || ^8.1
- laravel/framework: ^8.0 || ^9.0
Requires (Dev)
- nunomaduro/larastan: ^1.0 || ^2.0
- orchestra/testbench: ^6.23 || ^7.0
- dev-main
- 3.0.x-dev
- 2.2.24
- 2.2.1
- dev-feature/fix-readme-with-v3-changes-and-typos
- dev-hotfix/fix-missing-query-string-array
- dev-24-add-v3-0-changelog
- dev-26-fix-psr-12-code-style-errors
- dev-7-fix-syntax-based-on-phpstan-results
- dev-23-add-gitlab-ci-yml-file-with-gitlab-templates-for-code-quality-and-security-tests
- dev-18-v3-breaking-change-rename-package-from-glamstack-okta-sdk-to-gitlab-it-okta-sdk
- dev-19-fix-okta-pagination-results-to-include-first-200-results
- dev-20-add-gitlab-ci-yml-file-with-gitlab-templates-for-code-quality-and-security-tests
- dev-13-feature-update-sdk-to-allow-for-overriding-the-base_url-in-the-construct-method
- dev-15-add-changelog-2-2-24-md
- dev-11-add-changelog-2-2-1-md
- dev-9-add-calendar-versioning-calver-section-to-readme-md-and-contributing-md
- dev-2-add-apiclient-and-responselog-trait-with-updated-config-format
- dev-4-add-codeowners
- dev-3-update-readme-with-example-usage-details
This package is auto-updated.
Last update: 2023-02-26 20:57:13 UTC
README
[[目录]]
概览
Okta SDK 是 GitLab IT Engineering 为在内部 Laravel 应用程序中连接到 Okta 以进行用户、组、应用程序和其他相关功能的配置和取消配置而创建的开源 Composer 包。
免责声明:这不是由 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,该客户端可以执行 GET、POST、PUT 和 DELETE 请求到您在 Okta API 文档 中找到的任何端点,并为您处理 API 响应、错误处理和分页。
此功能基于由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', [
'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, [
'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
中的配置数组,允许您为每个连接到Okta API的连接配置基本URL、API令牌.env
变量名称和日志通道,并为该连接提供一个唯一的名称。
每个连接都关联有不同的基本URL和API令牌。
我们已经预配置了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
中添加额外的连接密钥(您选择的名称),并使用其他连接作为示例创建新的基本URL和API令牌变量。
基本URL
每个Okta客户都为其公司提供了一个子域。这有时被称为租户或API文档中的${yourOktaDomain}
。这应在prod
连接密钥或使用.env
变量中配置(见下文)。
https://mycompany.okta.com
如果您可以访问Okta预览沙盒/测试/预发布实例,您还可以在preview
连接密钥中配置基本URL和API令牌。
https://mycompany.oktapreview.com
如果您拥有免费的Okta开发者帐户,您可以在dev
密钥中配置基本URL和API令牌。
https://dev-12345678.okta.com
API令牌
请参阅Okta文档以创建API令牌。请注意,API令牌使用它所属用户的权限,因此对于生产应用程序用例,最好创建服务帐户(机器人)用户。任何30天内未进行API调用的令牌都会自动过期。
安全警告:请勿将API令牌添加到
config/okta-sdk.php
文件中,以避免将秘密提交到您的仓库(秘密泄露)。所有API令牌应定义在.env
文件中,该文件包含在.gitignore
中,并且不会被提交到您的仓库。对于高级用例,您可以将变量存储在CI/CD变量或秘密保险库中(此处未提供文档)。
内部开发人员备注:初始化SDK时,API密钥将自动以
SSWS
前缀。
默认全局连接
默认情况下,SDK将使用dev
连接密钥处理您应用程序中所有的API调用,除非您使用OKTA_DEFAULT_CONNECTION
变量覆盖默认连接到不同的连接密钥。
如果您刚开始使用,建议您将其保持为dev
,这样您就可以使用您的Okta开发者帐户使用此SDK。在将应用程序部署到预发布或生产环境时,您可以稍后将其更改为preview
或prod
。
OKTA_DEFAULT_CONNECTION="dev"
默认连接密钥变量
您可以使用任何组合的prod
、preview
或dev
连接密钥。请确保用您的URL替换mycompany
。
只需保留任何未使用的连接为空或从您的.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
提供连接密钥
。这允许您在不硬编码连接密钥的情况下构建应用程序,并简单地更新.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调用使用特定连接
如果您在使用ApiClient
时想要使用与OKTA_DEFAULT_CONNECTION
.env
变量不同的特定连接密钥
,则可以将已配置在config/okta-sdk.php
中的任何连接密钥
作为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基本URL多次添加到config/okta-sdk.php
中,并使用不同的连接键来自定义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请求
您可以向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', [
'name' => 'Hack the Planet Engineers',
'description' => 'This group contains engineers that have proven they are elite enough to hack the Gibson.'
]);
PUT 请求
put()
方法用于更新现有记录(类似于 PATCH
请求)。您需要确保您想要更新的记录的 ID 已提供在第一个参数(URI)中。
在大多数应用程序中,这将是从您的数据库或其他位置获取的变量,而不是硬编码的。
// Update a group
// https://developer.okta.com/docs/reference/api/groups/#update-group
$group_id = '0oa1ab2c3D4E5F6G7h8i';
$record = $okta_api->put('/groups/' . $group_id, [
'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了解如何贡献的更多信息。