ellaisys / aws-cognito
AWS Cognito 包,允许使用 AWS SDK for PHP 进行身份验证和其他相关功能
Requires
- php: ^7.0|^8.0
- aws/aws-sdk-php: >=3.0
- firebase/php-jwt: ^6.0
- guzzlehttp/guzzle: ^6.0|^7.0
Requires (Dev)
- phpunit/phpunit: >=9.0
- v1.3.0
- v1.2.5
- v1.2.4
- v1.2.3
- v1.2.2
- v1.2.1
- v1.2.0
- v1.1.6
- v1.1.5
- v1.1.4
- v1.1.3
- v1.1.2
- v1.1.1
- v1.1.0
- dev-master / 1.0.x-dev
- v1.0.11
- v1.0.10
- v1.0.9
- v1.0.8
- v1.0.7
- v1.0.6
- v1.0.5
- v1.0.4
- v1.0.3
- v1.0.2
- v1.0.1
- v1.0.0
- v0.1.13
- v0.1.12
- v0.1.11
- v0.1.10
- v0.1.9
- v0.1.8
- v0.1.7
- v0.1.6
- v0.1.5
- v0.1.4
- v0.1.3
- v0.1.2
- v0.1.1
- v0.1.0
- dev-70-add-web-views-as-partials
- dev-106-user-is-always-null-when-using-api-guard
- dev-hotfix
This package is auto-updated.
Last update: 2024-09-05 07:23:00 UTC
README
Laravel AWS Cognito 包,用于具有多因素认证功能的 Web 和 API 身份验证
使用 AWS SDK for PHP 的 AWS Cognito 包
此包提供了一种简单的方法,在 Laravel 中使用 AWS Cognito 身份验证进行 Web 和 API 身份验证驱动程序。此包的想法和一些代码基于 Pod-Point 的包,您可以在以下位置找到:[Pod-Point/laravel-cognito-auth](https://github.com/Pod-Point/laravel-cognito-auth)、[black-bits/laravel-cognito-auth](https://github.com/black-bits/laravel-cognito-auth) 和 [tymondesigns/jwt-auth](https://github.com/tymondesigns/jwt-auth)。
DEMO 应用程序。您可以尝试注册和登录。第一次登录时,将强制用户更改密码。该演示应用程序的 源代码 也可在 GitHub 上找到。
我们决定使用它并将其作为软件包贡献给社区,这个软件包鼓励标准化使用,并为使用AWS Cognito进行身份验证提供RAD(快速应用程序开发)工具。
特性
- 注册和确认电子邮件(注册)
- 首次登录强制更改密码(可配置)
- 登录(登录)
- 所有会话和令牌保护请求的令牌验证
- 记住我Cookie
- 单一登录 更新(修复:问题#86)
- 忘记密码(重新发送 - 可配置)
- 用户删除
- 编辑用户属性
- 重置用户密码
- 确认注册
- 简单的API令牌处理(使用缓存驱动程序)
- 支持Web会话和API令牌的DynamoDB(对于服务器冗余或多容器很有用)
- 简单的令牌过期配置(使用Cognito控制台管理,无需代码或配置)
- 支持无秘密的应用客户端
- 支持Cognito组,包括为新用户分配默认组
- 会话(Web)现在将AccessToken和RefreshToken作为声明对象的一部分
- 注销(登出) - 从AWS移除访问令牌
- 强制注销(登出) - 从AWS撤销RefreshToken
- 会话和令牌保护器的MFA实现
- 基于Cognito配置的密码验证
- 使用Subject UUID映射Cognito用户 新功能
兼容性
安装
您可以通过composer安装此软件包。
composer require ellaisys/aws-cognito
Laravel 5.4及之前版本
使用Laravel 5.5之前的版本,您需要手动注册服务提供程序。
// config/app.php 'providers' => [ ... Ellaisys\Cognito\Providers\AwsCognitoServiceProvider::class, ];
配置文件:接下来,您可以发布配置。
php artisan vendor:publish --provider="Ellaisys\Cognito\Providers\AwsCognitoServiceProvider"
最后但同样重要的是,您想要更改认证驱动程序。要做到这一点,请转到您的config\auth.php文件,并将其更改为以下内容
'guards' => [ 'web' => [ 'driver' => 'cognito-session', // This line is important for using AWS Cognito as Web Driver 'provider' => 'users', ], 'api' => [ 'driver' => 'cognito-token', // This line is important for using AWS Cognito as API Driver 'provider' => 'users', ], ],
重要
这是一个在V1.2.0中发布的新功能,应与Laravel 8.37(具有匿名迁移支持)一起工作。对于低于Laravel 8.37的版本,此功能已禁用。您需要更新users表迁移,并添加列(类型:string,可空:是,索引:是)。
数据库迁移
AWS Cognito服务提供程序注册了自己的数据库迁移目录,因此请记住在安装软件包后迁移您的数据库。AWS Cognito迁移将在您的users表中添加一些列。
php artisan migrate
如果您需要覆盖AWS Cognito提供的迁移,可以使用vendor:publish Artisan命令发布它们。
php artisan vendor:publish --tag="cognito-migrations"
如果您希望完全阻止AWS Cognito的迁移运行,可以使用AWS Cognito提供的ignoreMigrations方法。通常,此方法应在您的AppServiceProvider的register方法中调用。
use Ellaisys\Cognito\AwsCognito; /** * Register any application services. */ public function register(): void { AwsCognito::ignoreMigrations(); }
Cognito用户池
为了将AWS Cognito用作认证提供程序,您需要一个Cognito用户池。
如果您还没有创建一个,请转到您的Amazon管理控制台并创建一个新的用户池。
接下来,生成一个App客户端。这将为您提供在.env
文件中需要的App客户端ID和App客户端秘密。
重要:不要忘记激活“启用基于服务器的认证的登录API”的复选框。认证流程称为:ADMIN_USER_PASSWORD_AUTH(以前称为ADMIN_NO_SRP_AUTH)。
AWS IAM配置
您还需要一个新的具有以下访问权限的IAM角色
- AmazonCognitoDeveloperAuthenticatedIdentities
- AmazonCognitoPowerUser
- AmazonESCognitoAccess
从此IAM用户开始,您必须在laravel环境文件中使用AWS_ACCESS_KEY_ID和AWS_SECRET_ACCESS_KEY。
Cognito配置
将以下字段添加到您的 .env
文件中,并根据您的 AWS 设置设置值
# AWS configurations for cloud storage AWS_ACCESS_KEY_ID="Axxxxxxxxxxxxxxxxxxxxxxxx6" AWS_SECRET_ACCESS_KEY="mxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx+" # AWS Cognito configurations AWS_COGNITO_CLIENT_ID="6xxxxxxxxxxxxxxxxxxxxxxxxr" AWS_COGNITO_CLIENT_SECRET="1xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx1" AWS_COGNITO_USER_POOL_ID="xxxxxxxxxxxxxxxxx" AWS_COGNITO_REGION="xxxxxxxxxxx" //optional - default value is 'us-east-1' AWS_COGNITO_VERSION="latest" //optional - default value is 'latest'
重要
为了同步 Web 会话超时与 Cognito 访问令牌 TTL 值,请设置 .env 文件中的 SESSION_LIFETIME 参数。此值为分钟,默认值为 120 分钟,即 2 小时。这将确保 Laravel 会话与访问令牌同时超时。
有关如何为您的应用程序找到 AWS_COGNITO_CLIENT_ID、AWS_COGNITO_CLIENT_SECRET 和 AWS_COGNITO_USER_POOL_ID 的更多详细信息,请参阅 COGNITOCONFIG 文件
将现有用户导入 Cognito 池
如果您已经在现有的项目中工作,并想集成 Cognito,您必须 将用户 CSV 文件导入您的 Cognito 池。
用法
我们的包为您提供了 6 个特质,您只需将它们添加到您的 Auth 控制器中即可运行我们的包。
- Ellaisys\Cognito\Auth\AuthenticatesUsers
- Ellaisys\Cognito\Auth\RegistersUsers
- Ellaisys\Cognito\Auth\ResetsPasswords
- Ellaisys\Cognito\Auth\RespondsMFAChallenge
- Ellaisys\Cognito\Auth\SendsPasswordResetEmails
- Ellaisys\Cognito\Auth\VerifiesEmails
以最简单的方式,您只需遍历您的 Auth 控制器,并将特质中的命名空间从当前实现的 Laravel 命名空间更改。
您可以根据需要更改结构。请注意 blade 文件中的 @extend 语句以适应您的项目结构。在当前状态下,您需要在这里定义这 4 个表单字段:token、email、password、password_confirmation。
单点登录
借助我们的包和 AWS Cognito,我们为您提供了一种简单的方式来使用单点登录。有关配置选项,请查看配置 cognito.php。
当您想要启用 SSO 并用户尝试登录您的应用程序时,该包会检查用户是否存在于您的 AWS Cognito 池中。如果用户存在,并且设置了 add_missing_local_user
为 true
,则用户将自动在您的数据库中创建,并且可以同时登录。
这就是我们使用 sso_user_model
和 cognito_user_fields
字段的原因。在 sso_user_model
中,您定义用户模型的类。在大多数情况下,这将是简单地 App\Models\User。
使用 cognito_user_fields
您可以定义应该存储在 Cognito 中的字段。请注意。如果您定义了一个在注册请求中未发送的字段,这将抛出 InvalidUserFieldException,并且您将无法注册。
现在您已经将用户及其属性注册到 AWS Cognito 池和数据库中,并且您想要附加第二个应使用相同池的应用程序。实际上,这实际上非常简单。您可以使用允许多个项目消耗相同 AWS Cognito 池的 API 规范。
**重要提示**:如果您的用户表中有密码字段,您将不再需要它。您想要做的是将此字段设置为可空,以便可以在没有密码的情况下创建用户。从现在起,密码将存储在 Cognito 中。
您具有的任何其他注册数据,例如 firstname
、lastname
,需要添加到 cognito.php 中的 cognito_user_fields 配置以推送到 Cognito。否则,它们只会在本地存储,并且如果您想使用单点登录,则不可用。
忘记密码并重新发送选项
如果用户尚未激活账户,AWS Cognito 默认功能不允许用户使用忘记密码功能。我们引入了 AWS 文档中记录的功能,允许重新发送密码。
我们已将该配置项设置为可配置,以便开发者根据业务需求使用。配置项接受布尔值。默认为true(允许重发忘记密码)。
AWS_COGNITO_ALLOW_FORGOT_PASSWORD_RESEND=true
API路由的中间件配置
如果您将此库用作API驱动程序,可以将中间件注册到kernal.php中的$routeMiddleware。
protected $routeMiddleware = [ ... 'aws-cognito' => \Ellaisys\Cognito\Http\Middleware\AwsCognitoAuthenticate::class ]
要使用中间件在<强>Web路由强>中,可以使用以下标准身份验证中间件
Route::middleware('auth')->get('user', 'NameOfTheController@functionName');
要使用中间件在<强>API路由强>中,如下所示
Route::middleware('aws-cognito')->get('user', 'NameOfTheController@functionName');
注册用户
默认情况下,如果您使用Cognito注册新用户,Cognito将在signUp期间发送包含用户名和临时密码的电子邮件,以便用户验证自己。
结合使用此库和<强>AWS Lambda强>,可以自定义电子邮件模板和内容。电子邮件模板可以是文本或HTML格式。Lambda代码不包括在此代码库中。您可以创建自己的。您传递给注册方法的任何对象(数组)都将直接传递到Lambda函数,我们不对属性名称进行指定。
我们使任何人都可以轻松使用默认行为。
- 您不需要创建额外的字段来存储验证令牌。
- 您无需担心会话或API令牌,它们由Laravel的标准机制为您管理。您可以将其保存在任何地方,没有任何安全漏洞。
- 如果您使用我们提供的'trait Ellaisys\Cognito\Auth\RegistersUsers',代码将仅限于几行
- 如果您正在使用Laravel脚手架,请在数据库中将密码设置为可选的或在模式中删除它。密码将仅由AWS Cognito管理。
use Ellaisys\Cognito\Auth\RegistersUsers; class UserController extends BaseController { use RegistersUsers; public function register(Request $request) { $validator = $request->validate([ 'name' => 'required|max:255', 'email' => 'required|email|max:64|unique:users', 'password' => 'sometimes|confirmed|min:6|max:64', ]); //Create credentials object $collection = collect($request->all()); $data = $collection->only('name', 'email', 'password'); //passing 'password' is optional. //Register User in cognito if ($cognitoRegistered=$this->createCognitoUser($data)) { //If successful, create the user in local db User::create($collection->only('name', 'email')); } //End if //Redirect to view return view('login'); } }
-
您不需要关闭Cognito来发送电子邮件。我们建议使用AWS Cognito或AWS SMS邮件发送者,以确保用户凭证始终安全。
-
如果您想抑制发送给新用户的邮件,可以配置以下参数以跳过新用户注册的欢迎邮件。默认配置将发送欢迎邮件。
AWS_COGNITO_NEW_USER_MESSAGE_ACTION="SUPPRESS"
- 以下配置允许新用户的电子邮件地址自动标记为已验证。
AWS_COGNITO_FORCE_NEW_USER_EMAIL_VERIFIED=true //optional - default value is false.
- 要将默认组分配给新用户,在注册时设置用户组的名称,该名称是通过AWS Cognito管理控制台进行的配置。默认值设置为null。
AWS_COGNITO_DEFAULT_USER_GROUP="Customers"
- 要启用自定义密码或用户定义的密码,如果以下配置设置为<强>true强>,则将强制用户在注册时设置密码,否则Cognito将生成随机密码并通过电子邮件和/或短信发送,具体取决于配置。
AWS_COGNITO_FORCE_NEW_USER_PASSWORD=true //optional - default value is false.
用户身份验证
我们提供了一种有用的特性,使身份验证非常简单(适用于Web或API路由)。您无需担心管理会话和令牌(对于API)的任何额外代码。
注意
访问令牌现在与AWS Cognito证书进行验证。如果证书不正确或已过期,将抛出异常。
该特性接受一些附加参数,请参阅以下特性的函数签名。请注意,该函数接受
此外,通过传递'guard'名称引用,您可以在项目中重用该函数以多个守卫驱动程序。该函数具有处理多个驱动程序和提供程序的能力,这些驱动程序和提供程序在/config/auth.php中定义。
namespace Ellaisys\Cognito\Auth; protected function attemptLogin ( Collection $request, string $guard='web', string $paramUsername='email', string $paramPassword='password', bool $isJsonResponse=false ) { ... ... ... }
如果您想将此特性用于Web登录,可以在AuthController.php中编写以下代码
namespace App\Http\Controllers; ... use Ellaisys\Cognito\AwsCognitoClaim; use Ellaisys\Cognito\Auth\AuthenticatesUsers as CognitoAuthenticatesUsers; class AuthController extends Controller { use CognitoAuthenticatesUsers; /** * Authenticate User * * @throws \HttpException * * @return mixed */ public function login(\Illuminate\Http\Request $request) { ... //Convert request to collection $collection = collect($request->all()); //Authenticate with Cognito Package Trait (with 'web' as the auth guard) if ($response = $this->attemptLogin($collection, 'web')) { if ($response===true) { return redirect(route('home'))->with('success', true); } else if ($response===false) { // If the login attempt was unsuccessful you may increment the number of attempts // to login and redirect the user back to the login form. Of course, when this // user surpasses their maximum number of attempts they will get locked out. // //$this->incrementLoginAttempts($request); // //$this->sendFailedLoginResponse($collection, null); } else { return $response; } //End if } //End if } //Function ends ... } //Class ends
如果您想使用此特征进行基于API的登录,您可以在AuthApiController.php中按照以下代码编写:
namespace App\Api\Controller; ... use Ellaisys\Cognito\AwsCognitoClaim; use Ellaisys\Cognito\Auth\AuthenticatesUsers as CognitoAuthenticatesUsers; class AuthApiController extends Controller { use CognitoAuthenticatesUsers; /** * Authenticate User * * @throws \HttpException * * @return mixed */ public function login(\Illuminate\Http\Request $request) { ... //Convert request to collection $collection = collect($request->all()); //Authenticate with Cognito Package Trait (with 'api' as the auth guard) if ($claim = $this->attemptLogin($collection, 'api', 'username', 'password', true)) { if ($claim instanceof AwsCognitoClaim) { return $claim->getData(); } else { return response()->json(['status' => 'error', 'message' => $claim], 400); } //End if } //End if } //Function ends ... } //Class ends
登出(移除访问令牌)
登出方法现在是守卫实现的一部分,登出方法会从AWS中移除访问令牌,并从由该库管理的应用程序存储中移除。只需调用认证守卫的登出方法即可。您可以根据开发偏好将其实现到路由或控制器中。
现在,登出方法接受一个可选的布尔参数(true),用于撤销刷新令牌。默认值为(false),这将使刷新令牌持续存在于AWS Cognito中。
... Auth::guard('api')->logout(); ... Auth::guard('api')->logout(true); //Revoke the Refresh Token.
刷新令牌
您可以使用此特征为API生成新的令牌。
namespace App\Api\Controller; ... use Ellaisys\Cognito\AwsCognitoClaim; use Ellaisys\Cognito\Auth\RefreshToken; class AuthApiController extends Controller { use RefreshToken; /** * Generate a new token using refresh token. * * @throws \HttpException * * @return mixed */ public function refreshToken(\Illuminate\Http\Request $request) { ... $validator = $request->validate([ 'email' => 'required|email', 'refresh_token' => 'required' ]); try { return $this->refresh($request, 'email', 'refresh_token'); } catch (Exception $e) { return $e; } } //Function ends ... } //Class ends
删除用户
如果您想允许用户从您的应用程序中删除自己,您可以使用我们的deleteUser函数从CognitoClient中。
要删除用户,您应该调用deleteUser并传递用户的电子邮件地址作为参数。在您的cognito池中删除用户后,也应从您的数据库中删除该用户。
$cognitoClient->deleteUser($user->email); $user->delete();
我们实现了一个新的配置选项delete_user
,您可以通过AWS_COGNITO_DELETE_USER
环境变量访问。如果您将此配置设置为true,则用户将在cognito池中被删除。如果设置为false,则用户将保持注册状态。默认情况下,此选项设置为false。如果您想实现这种行为,应将USE_SSO设置为true,以便用户在成功登录后恢复自己。
要访问我们的CognitoClient,您只需将其作为参数传递到您想要执行删除操作的控制器操作中。
public function deleteUser(Request $request, AwsCognitoClient $client)
Laravel将自动处理依赖注入。
IMPORTANT: You want to secure this action by maybe security questions, a second delete password or by confirming
the email address.
在DynamoDB中存储Web会话或API令牌(适用于多服务器/容器实现)
如果您有一个涉及多个服务器且需要在服务器之间维护Web会话或API令牌的部署架构,您可以使用AWS DynamoDB。该库可以轻松处理DynamoDB。您需要做的只是创建AWS DynamoDB中的表并更改一些配置。
在AWS DynamoDB中创建一个新表
- 转到AWS控制台并创建一个新表。
- 输入您偏好的唯一表名。
- 主键(或分区键)应该是类型为字符串的key。
- 使用默认设置并单击创建按钮。
更新Dynamo DB配置的.env文件
将以下字段添加到您的.env
文件中,并根据您的AWS设置设置值
# Cache Configuration CACHE_DRIVER="dynamodb" DYNAMODB_CACHE_TABLE="table-name-of-your-choice" //This should match the table name provided above # Session Configuration SESSION_DRIVER="dynamodb" SESSION_LIFETIME=120 SESSION_DOMAIN="set-your-domain-name" //The domain name can be as per your preference SESSION_SECURE_COOKIE=true # DynamoDB Configuration DYNAMODB_ENDPOINT="https://dynamodb.us-west-2.amazonaws.com" // You can change the endpoint based of different regions
参考AWS DynamoDB文档,并参考在服务端点部分提供的端点。
更新DynamoDB表的TTL列,将其更改为expires_at。
API使用中的自动用户密码更新(适用于新Cognito用户)
对于新Cognito用户,AWS SDK将发送一个会话密钥,并期望用户以强制模式更改密码。请确保您强制新Cognito用户在首次登录时更改密码。
然而,如果您有基于API的实现,并希望在不强制更改密码的情况下自动认证用户,您可以通过以下设置字段来实现,将其添加到您的.env
文件中:
AWS_COGNITO_FORCE_PASSWORD_CHANGE_API=false //Make true for forcing password change AWS_COGNITO_FORCE_PASSWORD_AUTO_UPDATE_API=true //Make false for stopping auto password change
支持未启用Secret的应用客户端
现在,该库支持AWS配置中的应用客户端,其中客户端密钥设置为禁用。使用以下环境文件配置启用/禁用此功能。默认设置为启用(即我们期望在AWS Cognito配置中启用App客户端密钥)。
AWS_COGNITO_CLIENT_SECRET_ALLOW=false
基于Cognito配置的密码验证
此库从Cognito池配置中获取密码策略。基于此策略创建的正则表达式用于Laravel请求验证。这些验证在注册(注册)、登录(登录)、重置和更改密码流程期间执行。密码的验证信息也是动态的,并根据配置进行更改。
重要
目前,我们支持所有特殊字符,除了竖线字符 |。
使用Subject UUID映射Cognito用户
该库将Cognito用户主题UUID映射到本地存储库。每次在Cognito中创建新用户时,都会将sub UUID与本地用户表中的用户指定列名进行映射。
本地数据库中的列通过配置参数 user_subject_uuid
识别,默认值设置为 sub
。
然而,要自定义本地数据库用户表中的列名,您可以通过以下设置字段将它们添加到 .env
文件中
AWS_COGNITO_USER_SUBJECT_UUID="sub"
我们正在努力尽快处理竖线字符。
变更日志
有关最近更改的更多信息,请参阅 CHANGELOG。
安全
如果您发现任何安全相关的问题,请通过电子邮件发送到 support@ellaisys.com,并将其添加到问题跟踪器。
路线图
https://github.com/ellaisys/aws-cognito/wiki/RoadMap
如何贡献
- 在GitHub上星标此项目。
- 通过创建新问题或向现有问题添加评论来报告错误或建议功能
- 提交拉取请求
- 通过在博客中介绍SimplCommerce或在其社交网络上分享来传播信息
- 向我们捐赠
致谢 & 贡献者
本项目之所以存在,多亏了所有贡献者。
点击这些徽章了解您如何提供帮助
支持我们
EllaiSys曾是一家专注于云计算(AWS和Azure)、DevOps和产品工程的网络和咨询公司。我们从2021年10月起关闭了专业服务,但团队继续支持开源项目,这是我们对我们社区的承诺。任何有兴趣支持开发的人士都欢迎加入。
许可证
MIT许可证(MIT)。有关更多信息,请参阅许可证文件。
免责声明
该软件包目前处于生产就绪模式,已有几个实施案例。我们很高兴听到您关于缺陷或新功能改进的意见。然而,鉴于这是免费支持,我们无法承诺支持服务级别协议或时间表。