idata / idata_cognito
内部使用的aws cognito插件
Requires
- aws/aws-sdk-php: ^3.54
- cakephp/cakephp: 3.*
- evil-corp/cakephp-awsapigateway: 2.3.*
- evil-corp/cakephp-awss3upload: 1.0.*
- friendsofcake/search: ^3.1
- lcobucci/jwt: ^3.2
- muffin/footprint: ^1.2
- ralouphie/mimey: ^2.0
Requires (Dev)
- phpunit/phpunit: ^5.7|^6.0
This package is auto-updated.
Last update: 2024-09-05 01:01:00 UTC
README
此插件允许从应用程序面板管理AWS Cognito用户,确保其与本地副本同步。
此插件假设与AWS Cognito的单向通信通道,其中同步字段的更改首先在应用程序中发生,然后由插件传播到AWS Cognito。
变更日志
日期:2020-04-30
- 更新cakephp依赖项
日期:2018-10-11
- 重写了全部文档以反映最近的更改
文档
- 功能
- 备注
- 安装
- 结构
- EvilCorp\AwsCognito\Model\Entity\ApiUser
- EvilCorp\AwsCognito\Model\Table\ApiUsersTable
- EvilCorp\AwsCognito\Model\Traits\AwsCognitoSaveTrait
- EvilCorp\AwsCognito\Model\Behavior\AwsCognitoBehavior
- EvilCorp\AwsCognito\Model\Behavior\ImportApiUsersBehavior
- EvilCorp\AwsCognito\Controller\ApiUsersController
- EvilCorp\AwsCognito\Controller\Api\ApiUsersController
- EvilCorp\AwsCognito\Controller\Traits\BaseApiEndpointsTrait
- 配置变量
- 测试
- 扩展插件
功能
已实现
- 用户注册。向用户发送包含临时密码的邀请邮件
- 删除用户,确保也从Cognito中删除
- 通过“活跃”复选框禁用/启用用户(阻止登录)
- 密码重置
- 更改电子邮件,可以选择是否发送验证码
- 重新发送邀请邮件(创建账户)
- 用户配置文件指示用户是否与Cognito正确同步
- 将用户头像上传到AWS S3
- JSON Web Tokens (AwsCognitoJwtAuthenticate)身份验证器,用于验证Cognito用户
- 非管理员用户的API端点
- 以CSV格式批量导入用户,先进行验证
待办事项
- 配置以使用电话、电子邮件或两者进行用户注册/访问(目前仅支持电子邮件)
- 如果导入用户时发生错误,用户导入尚不能回滚编辑。为了避免冲突,请仅使用它来创建新用户。
- 允许管理员更改用户头像
备注
- 如果创建用户时该用户被创建为“禁用”(
active = 0
),则插件将在创建后尝试在Cognito中禁用它(因为不能在Cognito中创建禁用用户)。如果失败,则插件将优先考虑一致性,并将创建活跃用户。
安装
要使用composer获取插件,需要将以下内容添加到composer.json
:
- 向
"require"
对象添加插件:"evil-corp/cakephp-awscognito": "dev-master"
- 向
"repositories"
数组添加对象:{}
`
{"type": "vcs", "url": "git@bitbucket.org:evil-corp/cakephp-awscognito.git"}`
- 运行
composer update
注意:确保在存储库中具有正确的访问/部署权限。
一旦在存储库中安装了插件
- 将以下行添加到
config/bootstrap.php
以加载插件:Plugin::load('EvilCorp/AwsCognito', ['bootstrap' => true, 'routes' => true]);
- 确保存在
api_users
表。插件提供了迁移脚本,如果需要的话:bin/cake migrations migrate -p EvilCorp/AwsCognito
- 在Cognito中创建一个用户池。注意
- 用户池应仅包含访问所需的数据。额外的字段应仅存在于本地表中。
- 请确保Cognito创建用户所需字段的验证与本地表的验证相同或更宽松,否则在创建用户时可能会发生错误,这些错误不会正确显示给用户。
- 不允许用户通过Cognito更改其电子邮件或电话号码,这可能会导致数据不同步。除密码更改外,所有对用户所做的更改都应通过插件提供的API进行。
- 在加载插件之前,将以下行添加到 config/bootstrap.php 中:
Configure::write('AwsCognito.config', ['awscognito']);
- 将文件
vendor/evil-corp/cakephp-awscognito/config/awscognito.php
复制到app/config/awscognito.php
。 - 修改该文件以配置插件。(请参阅“配置变量”部分)
- 默认路由如下(要更改此设置,请参阅“扩展插件”部分。要禁用默认路由,请在
Plugin::load
中使用'routes' => false
)- 插件的用户控制器应可通过
/aws-cognito/api-users
访问 - API端点可通过
/aws-cognito/api/api-users/:action
访问
- 插件的用户控制器应可通过
结构
EvilCorp\AwsCognito\Model\Entity\ApiUser
属性
- aws_cognito_id (char 36) (隐藏,不可变)
- aws_cognito_username (varchar 255) (隐藏,不可变)
- email (varchar 255)
- active (tinyint 1)
- role (varchar 50)
- first_name (varchar 50)
- last_name (varchar 50)
- created (datetime)
- modified (datetime)
虚拟属性
- full_name (
"${first_name} ${last_name}"
)
EvilCorp\AwsCognito\Model\Table\ApiUsersTable
- 受保护的 $searchQueryFields
- 用于表搜索配置的字段数组。
- 抽象为受保护的属性以简化扩展。
- 公共的 initialize()
- 配置与
Users
表的Creators
关联以及与Users
表的Modifiers
关联(created_by)。要更改使用的表,必须扩展表,请参阅“扩展插件”部分。 - 添加
Timestamp
行为以填充字段created_at
和modified_at
- 添加
Muffin/Footprint.Footprint
行为以填充字段created_by
和modified_by
- 添加
EvilCorp/AwsCognito.AwsCognito
行为以启用Cognito功能 - 添加
EvilCorp/AwsCognito.ImportApiUsers
行为以添加批量导入功能 - 添加
EvilCorp/AwsS3Upload.AwsS3Upload
行为以将用户头像上传到AWS S3 - 添加
Search.Search
行为以启用搜索
- 配置与
- 公共的 validationDefault(Validator $validator)
- 基本验证字段(id,first_name,last_name)
- 确保字段
role
存在且属于配置的列表(要更改此设置,必须扩展验证,请参阅“扩展插件”部分)。
- 公共的 getRoles()
- 返回配置的角色的数组。
- 如果配置不存在或无效,则抛出异常。
EvilCorp\AwsCognito\Model\Traits\AwsCognitoSaveTrait
此trait由ApiUsersTable使用。其功能是
- 覆盖
saveMany
方法以捕获在尝试同时保存多个用户时发生的任何Cognito异常或保存错误。 - 在这种情况下,它负责回滚在Cognito中引起的变化,如有必要,删除新用户。
- 将来还应负责回滚编辑。
EvilCorp\AwsCognito\Model\Behavior\AwsCognitoBehavior
此Behavior负责启用与Cognito相关的所有功能。其方法如下
- 公共的 validationResendInvitationEmail(Validator $validator)
- 用于重新发送邀请电子邮件动作的验证器
- 公共的 validationChangeEmail(Validator $validator)
- 用于更改电子邮件动作的验证器
- public buildValidator(Event $event, Validator $validator, $name)
- 验证器回调
- 确保字段在相应的条件下被要求和验证
- public buildRules(Event $event, RulesChecker $rules)
- 添加应用规则
- 确保Cognito用户名唯一
- 确保电子邮件地址唯一
- 阻止编辑Cognito用户名
- 阻止编辑Cognito ID
- 阻止通过传统方式编辑电子邮件(有一个选项允许changeEmail和resendInvitationEmail方法更改它)
- public beforeSave(Event $event, EntityInterface $entity, ArrayObject $options)
- 在保存用户之前,此回调执行以下操作
- 如果用户是新的,则调用
createCognitoUser
- 如果用户正在编辑并且
active
字段已更改,则根据需要调用disableCognitoUser
或enableCognitoUser
- 如果用户是新的,则调用
- 在保存用户之前,此回调执行以下操作
- public beforeDelete(Event $event, EntityInterface $entity, ArrayObject $options)
- 在从数据库中删除用户之前,此回调调用
deleteCognitoUser
以在Cognito中删除它。
- 在从数据库中删除用户之前,此回调调用
- public changeEmail(EntityInterface $entity, $new_email, bool $require_verification = true)
- 此方法封装了用户电子邮件地址的更改,以便可以从Controller轻松调用。
- 在Cognito中更改电子邮件地址,并在成功的情况下将更改保存到数据库中。
- 允许通过参数
$require_verification
选择电子邮件是否需要验证。 - 如果需要验证,Cognito将向用户发送带有验证码的电子邮件。客户端开发者可以使用此验证电子邮件。
- public resendInvitationEmail(EntityInterface $entity, $new_email)
- 如果账户已过期(刷新它)或电子邮件地址不正确(允许更改它),则重新发送邀请电子邮件。
- public getWithCognitoData($id, $options = [])
- 在数据库中查找用户并添加Cognito信息
- 调用Cognito来添加字段,因此性能不高。
- 用于Controller中的客户详情。
- 添加以下字段
- bool
aws_cognito_synced
:指示用户是否已正确将所有相关字段同步到Cognito。通常不应为假。 - array
aws_cognito_attributes
:Cognito额外属性列表 - array
aws_cognito_status
:包含显示Cognito状态的字段,已解析以便更易读aws_cognito_status['code']
:状态代码aws_cognito_status['title']
:状态标题aws_cognito_status['description']
:状态描述
- bool
- 如果在Cognito中找不到用户,则不会抛出异常,而是字段为空,且
aws_cognito_synced
将为假。
- public resetCognitoPassword(EntityInterface $entity)
- 清除密码。
- 将在用户下次登录时启动更改密码过程。
- 如果用户从未登录过,或如果电子邮件/电话未验证以发送验证消息,则无法清除密码。
- public deleteCognitoUser(EntityInterface $entity)
- 从Cognito删除用户。
- 在从本地表中删除用户时自动使用。
- 此方法是公开的,因为对于批量处理和事务处理过程很有用。
- protected createCognitoClient()
- 内部方法,用于初始化与Cognito的连接。
- protected processCognitoUser(Result $cognito_user)
- 处理Cognito SDK返回的用户数据,并将其转换为更符合CakePHP格式的数据。
- protected titleForUserStatus($status)
- 返回Cognito用户状态标题
- protected descriptionForUserStatus($status)
- 返回Cognito用户状态描述
- 受保护 createCognitoUser(EntityInterface $entity, $message_action = null)
- 用于在Cognito中创建新用户,或重新发送邀请电子邮件
- 受保护 awsExceptionToEntityErrors(AwsException $exception, EntityInterface $entity)
- 解析Cognito的一些异常,并将它们转换为实体的验证错误
- 覆盖电子邮件和用户无效或重复的情况
- 由其他方法使用,以使过程更加CakePHP友好
- 受保护 disableCognitoUser(EntityInterface $entity)
- 在Cognito中禁用用户,阻止其登录
- 受保护 enableCognitoUser(EntityInterface $entity)
- 在Cognito中启用用户,恢复其登录
EvilCorp\AwsCognito\Model\Behavior\ImportApiUsersBehavior
此Behavior负责添加用户导入功能。目前,这包括批量导入用户的能力,以CSV格式。其方法如下
- 公共 validateMany(array $rows, $max_errors = false, array $options = []): array
$rows
是一个用户数组,可能包含CakePHP实体或格式化为CakePHP的用户数据的数组- 此方法将数组中输入的
$rows
中的所有用户转换为CakePHP实体 - 使用用户名来查找现有的实体,并使用输入的更改进行修补。其余的将创建。
- 使用实体验证和应用程序规则验证所有实体
- 还检查它们之间是否存在重复项
- 返回一个包含所有验证的实体数组。可以通过调用
$entity->getErrors()
来查看错误
- 公共 csvDataToAssociativeArray(string $csv_data, array $fields = []): array
- 将输入的CSV格式数据
$csv_data
转换为格式化以供CakePHP使用的用户数组 - 期望字段按特定顺序排列
- 默认期望基本字段(
aws_cognito_username
、email
、first_name
、last_name
) - 要更改顺序或字段数量,请使用参数$fields。
- 将输入的CSV格式数据
EvilCorp\AwsCognito\Controller\ApiUsersController
使用以下Trait
BaseCrudTrait
ImportApiUsersTrait
AwsCognitoTrait
EvilCorp\AwsCognito\Controller\Traits\BaseCrudTrait
提供以下基本管理员用户操作
- /aws-cognito/api-users/index (GET)
- 用户列表
- /aws-cognito/api-users/view/:id (GET)
- 用户详情
- 包含Cognito数据
- /aws-cognito/api-users/add (GET, POST)
- 添加用户
- /aws-cognito/api-users/edit/:id (GET, POST)
- 编辑用户的基本字段(first_name、last_name等)
- /aws-cognito/api-users/change-email/:id (GET, POST)
- 更改用户电子邮件
- 允许决定电子邮件是否需要验证(在这种情况下,将发送验证电子邮件)
- /aws-cognito/api-users/delete/:id (POST, DELETE)
- 删除用户
EvilCorp\AwsCognito\Controller\Traits\ImportApiUsersTrait
提供用户导入操作
- /aws-cognito/api-users/import (GET, POST)
- 允许通过CSV格式的文本字段批量导入用户
EvilCorp\AwsCognito\Controller\Traits\AwsCognitoTrait
提供与Cognito功能相关的操作
- /aws-cognito/api-users/activate/:id (POST)
- 激活用户(允许登录)
- /aws-cognito/api-users/deactivate/:id (POST)
- 停用用户(阻止登录)
- /aws-cognito/api-users/reset-password/:id (POST)
- 清除用户密码
- 将在用户下次登录时启动更改密码过程。
- 如果用户从未登录过,或如果电子邮件/电话未验证以发送验证消息,则无法清除密码。
- /aws-cognito/api-users/resend-invitation-email/:id (GET, POST)
- 重新发送邀请电子邮件
- 刷新账户到期时间
- 允许更改电子邮件
EvilCorp\AwsCognito\Controller\Api\ApiUsersController
使用BaseApiEndpointsTrait
。
EvilCorp\AwsCognito\Controller\Traits\BaseApiEndpointsTrait
为客户端开发者提供以下端点
- /aws-cognito/api/api-users/profile (GET)
- 用户详情
- /aws-cognito/api/api-users/profile (POST)
- 允许编辑用户资料(仅基本字段,如first_name和last_name)
- /aws-cognito/api/api-users/change-email (POST)
- 允许更改用户邮箱
- 将发送带有验证码的邮件到新邮箱地址。开发者需要使用该验证码与cognito通信并验证邮箱。
- /aws-cognito/api/api-users/upload-avatar (POST)
- 允许更改用户头像
- 期望在HTTP请求体中发送原始图像二进制数据
- 将头像上传到S3
配置变量
配置变量与应用程序的配置数组中的其他配置一起保存(默认为config/app.php
)。
可用的配置有
'AwsCognito' => [
'AccessKeys' => [
'id' => 'NSWPXE30F49XAOF',
'secret' => 'QIQNxRO2425bb040e4adc8cc02fae05063c3c'
],
'UserPool' => [
'id' => 'us-east-2_rjaob1HaR',
],
'IdentityProviderClient' => [
'settings' => [], //https://docs.aws.amazon.com/sdkforruby/api/Aws/CognitoIdentityProvider/Client.html#initialize-instance_method
],
],
'ApiUsers' => [
/* available user roles */
'roles' => [
'user' => __d('EvilCorp/AwsCognito', 'API User'),
],
/* the max amount of errors alloweds before the validation process of the imported data is halted */
'import_max_errors' => 10,
/* the limit of accepted rows in the importing CSV data */
'import_max_rows' => 500,
]
测试
目前该插件大约有90%的行覆盖率以及70%的方法和函数覆盖率。
要运行测试,必须单独下载仓库(以便composer注册开发模式)。运行composer install
来安装依赖,然后使用vendor/bin/phpunit
运行测试。
扩展插件
更改路由
要更改插件的默认路由(/aws-cognito/api-users),可以将以下内容添加到config/routes.php
中,必须在bootstrap.php
中通过Plugin::load
加载插件时首先设置'routes' => false
。
然后,可以在config/routes.php
中的基本作用域(/
)内使用以下内容。
将路由
/aws-cognito/api-users
替换为/api-users
$routes->connect('/api-users/*', [ 'plugin' => 'EvilCorp/AwsCognito', 'controller' => 'ApiUsers' ]); $routes->connect('/api-users/:action', [ 'plugin' => 'EvilCorp/AwsCognito', 'controller' => 'ApiUsers', 'action' => ':action' ]); $routes->connect('/api-users/:action/:id', [ 'plugin' => 'EvilCorp/AwsCognito', 'controller' => 'ApiUsers', 'action' => ':action' ], ['id' => '\d+', 'pass' => ['id']]);
对于REST API,可以按照以下方式替换
Router::prefix('api', function ($routes) { $routes->extensions(['json']); /* Api Users */ $routes->connect('/me', [ 'plugin' => 'EvilCorp/AwsCognito', 'prefix' => 'Api', 'controller' => 'ApiUsers', 'action' => 'profile', '_method' => 'GET' ]); $routes->connect('/me', [ 'plugin' => 'EvilCorp/AwsCognito', 'prefix' => 'Api', 'controller' => 'ApiUsers', 'action' => 'editProfile', '_method' => 'PATCH' ]); $routes->connect('/me/avatar', [ 'plugin' => 'EvilCorp/AwsCognito', 'prefix' => 'Api', 'controller' => 'ApiUsers', 'action' => 'uploadAvatar', '_method' => 'PUT' ]); $routes->connect('/me/email', [ 'plugin' => 'EvilCorp/AwsCognito', 'prefix' => 'Api', 'controller' => 'ApiUsers', 'action' => 'changeEmail', '_method' => 'PUT' ]); });
重写视图
为了在不扩展控制器的情况下覆盖模板,需要将新的模板放在以下位置
src/Template/Plugin/EvilCorp/AwsCognito/ApiUsers/*
例如,要替换index模板
src/Template/Plugin/EvilCorp/AwsCognito/ApiUsers/index.ctp
扩展控制器/模型
如果需要扩展控制器和模型(例如,向ApiUsers模型添加新的关联),则最佳做法如下
首先,扩展ApiUsersTable
//archivo: src/Model/Table/ApiUsersTable.php
namespace App\Model\Table;
use EvilCorp\AwsCognito\Model\Entity\ApiUser;
use EvilCorp\AwsCognito\Model\Table\ApiUsersTable as AwsApiUsersTable;
class ApiUsersTable extends AwsApiUsersTable
{
//esto solo es necesario si no se va a extender la Entidad
protected $_entityClass = 'EvilCorp\AwsCognito\Model\Entity\ApiUser';
public function initialize(array $config)
{
parent::initialize($config);
//cambiando la tabla de usuarioa administradores
$this->association('Creators')->className('AppUsers');
$this->association('Modifiers')->className('AppUsers');
//agregar nuevas asociaciones aca
$this->belongsToMany('FunctionalUnits', [
'through' => 'ApiUsersFunctionalUnits',
'saveStrategy' =>'append',
]);
//y podemos facilmente reconfigurar el search cambiando estos valores
$this->searchQueryFields = [
'ApiUsers.aws_cognito_username',
'ApiUsers.email',
'ApiUsers.phone',
'ApiUsers.first_name',
'ApiUsers.last_name',
];
}
//extendiendo la validación por defecto
public function validationDefault(Validator $validator)
{
$validator = parent::validationDefault($validator);
//se puede remover la validacion de un campo si no se usa
$validator->remove('role');
//y agregar campos nuevos
$validator
->scalar('phone')
->allowEmpty('phone');
return $validator;
}
}
然后扩展ApiUsersController
//archivo: src/Controller/ApiUsersController.php
namespace App\Controller;
use EvilCorp\AwsCognito\Controller\ApiUsersController as AwsApiUsersController;
use App\Model\Table\ApiUsersTable;
class ApiUsersController extends AwsApiUsersController
{
//aca se pueden agregar nuevas acciones o reemplazar las existentes
//por ejemplo el index:
public function index()
{
$this->paginate['contain'] = ['PointsOfSale'];
$this->set('api_users', $this->paginate('ApiUsers'));
$this->set('_serialize', ['api_users']);
}
}
可选地,可以扩展实体ApiUser
//archivo: src/Model/Entity/ApiUser.php
namespace App\Model\Entity;
use EvilCorp\AwsCognito\Model\Entity\ApiUser as AwsApiUser;
class ApiUser extends AwsApiUser
{
protected $_accessible = [
'*' => true,
'id' => false,
'role' => false,
//cognito fields:
'aws_cognito_username' => false,
'aws_cognito_id' => false,
'email' => false,
//dejando lo demás como viene, podemos agregar nuevos campos
'phone' => false
];
//podemos agregar nuevas virtual properties aca
}
现在,为了保留插件的模板并且只需添加新的模板(或要替换的模板),可以修改路由,使得新的操作使用此控制器,而其他操作则重定向到插件内的控制器
//el index lleva al nuevo controller
$routes->connect('/api-users', ['controller' => 'ApiUsers', 'action' => 'index']);
$routes->connect('/api-users/index', ['controller' => 'ApiUsers', 'action' => 'index']);
//las demas rutas llevan al controller del plugin
$routes->connect('/api-users/*', [
'plugin' => 'EvilCorp/AwsCognito', 'controller' => 'ApiUsers'
]);
$routes->connect('/api-users/:action', [
'plugin' => 'EvilCorp/AwsCognito', 'controller' => 'ApiUsers', 'action' => ':action'
]);
$routes->connect('/api-users/:action/:id', [
'plugin' => 'EvilCorp/AwsCognito', 'controller' => 'ApiUsers', 'action' => ':action'
], ['id' => '\d+', 'pass' => ['id']]);