trusfin / aws-cognito
AWS Cognito 包,允许使用 AWS SDK for PHP 进行身份验证和其他相关功能
Requires
- php: ^7.0|^8.0
- aws/aws-sdk-php: >=3.0
- guzzlehttp/guzzle: ^6.0|^7.0
Requires (Dev)
- phpunit/phpunit: >=9.0
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)。
演示应用程序。您可以尝试注册和登录。首次登录时,将强制用户更改密码。演示应用程序的 源代码 也可在 GitHub 上找到。
我们决定使用它并将其作为一个包贡献给社区,这个包鼓励标准化使用和 AWS Cognito 身份验证的 RAD 工具。
特性
- 注册和确认电子邮件(注册)
- 首次登录时强制更改密码(可配置)
- 登录(登录)
- 记住我Cookie
- 单一登录
- 忘记密码(重新发送 - 可配置)
- 用户删除
- 编辑用户属性
- 重置用户密码
- 确认注册
- 易于处理的 API 令牌(使用缓存驱动程序)
- 支持 Web 会话和 API 令牌的 DynamoDB(对服务器冗余或多容器非常有用)
- 易于配置令牌过期(使用 Cognito 控制台管理,无需代码或配置)
- 支持无秘密的应用客户端
- 支持 Cognito 组,包括为新用户分配默认组
- 会话(Web)现在将 AccessToken 和 RefreshToken 作为声明对象的一部分
- 注销(退出)- 从 AWS 中删除访问令牌
- 强制注销(退出)- 从 AWS 中吊销 RefreshToken (新功能)
兼容性
安装
您可以通过 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', ], ],
Cognito 用户池
为了使用 AWS Cognito 作为身份验证提供者,您需要一个 Cognito 用户池。
如果您还没有创建一个,请访问您的 [Amazon 管理控制台](https://console.aws.amazon.com/cognito/home) 并创建一个新的用户池。
接下来,生成一个应用客户端。这将为您提供用于 .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 API 配置
请将以下字段添加到您的 .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'
有关如何为您的应用程序找到 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_sso
设置为 true
,则他将被自动创建在您的数据库中,并且可以同时登录。
这就是我们使用 sso_user_model
和 cognito_user_fields
字段的原因。在 sso_user_model
中,您定义用户模型的类。在大多数情况下,这将简单地是 App\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的标准机制为您管理。您可以自由地将它们保留在您想要的位置,没有任何安全漏洞。
- 如果您使用我们提供的特质'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=false
- 在注册时为新用户分配默认组,请根据通过AWS Cognito管理控制台完成的配置设置用户组名称。默认值设置为null。
AWS_COGNITO_DEFAULT_USER_GROUP="Customers"
用户认证
我们提供了一种有用的特质,使认证非常简单(通过Web或API路由)。您不必担心任何额外的代码来管理会话和令牌(API)。
特质接受一些额外的参数,请参考特质的函数签名。请注意,函数接受的是Illuminate\Support\Collection对象,而不是Illuminate\Http\Request。这允许您在任何代码层中使用此函数。
此外,'guard'名称引用是传递的,因此您可以在项目中为多个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
注销(删除访问令牌)
注销方法现在是guard实现的一部分,注销方法从AWS中删除访问令牌,并从由本库管理的应用程序存储中删除。只需调用auth guard注销方法即可。您可以根据开发偏好将其实现到路由或控制器中。
注销方法现在接受一个可选的布尔参数(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 { if ($claim = $this->refresh($request, 'email', 'refresh_token')) { if ($claim instanceof AwsCognitoClaim) { return $claim->getData(); } else { if ($claim->getData()->error == 'cognito.validation.invalid_username') { return response()->json(['status' => 'error', 'message' => $claim->getData()], 400); } //End if } //End if } //End if } catch (CognitoIdentityProviderException $exception) { return response()->json(['status' => 'error', 'message' => 'Invalid refresh token.'], 400); } } //Function ends ... } //Class ends
删除用户
如果您想允许用户从您的应用程序中删除自己,您可以使用CognitoClient的deleteUser函数。
要删除用户,您应该调用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控制台并创建一个新的表。
- 输入您偏好的唯一表名。
- 主键(或分区键)应该是类型为
string
的key
。 - 使用默认设置并点击
创建
按钮。
更新DynamoDB配置的.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的App客户端
现在,库支持AWS配置中的App客户端,其中Client Secret设置为禁用。将以下配置添加到环境文件中以启用/禁用此功能。默认设置为启用(即我们期望App Client Secret在AWS Cognito配置中启用)
AWS_COGNITO_CLIENT_SECRET_ALLOW=false
变更日志
请参阅变更日志以获取有关最近更改的更多信息。
安全性
如果您发现任何安全相关的问题,请通过support@ellaisys.com发送电子邮件,并将其添加到问题跟踪器。
路线图
https://github.com/ellaisys/aws-cognito/wiki/RoadMap
如何贡献
- 在GitHub上星标此项目。
- 通过创建新问题或向问题添加评论来报告错误或建议功能
- 提交拉取请求
- 通过博客关于SimplCommerce或在社会网络上分享来传播信息
- 向我们捐赠
致谢 & 贡献者
此项目得益于所有贡献者。
支持我们
EllaiSys是一家专注于云计算(AWS和Azure)、DevOps和产品工程的网络和咨询公司。我们已于2021年10月关闭了专业服务产品,然而团队仍将继续支持开源项目,这是我们对社区的承诺。任何有兴趣支持开发的人士都欢迎加入。
许可证
MIT许可证(MIT)。请参阅许可证文件以获取更多信息。
免责声明
该软件包目前处于生产就绪模式,已经完成了一些实施。我们很高兴听取您关于缺陷或新功能改进的意见。然而,由于这是免费支持,我们无法承诺支持SLA或时间表。