shady-amir/laravel-aws-cognito-auth

为 Laravel 开发的认证驱动,用于在 AWS Cognito 用户池中通过 AWS API 网关辅助函数对用户进行身份验证,支持组和角色。

v1.2.2 2019-12-12 13:01 UTC

This package is auto-updated.

Last update: 2024-09-13 00:12:14 UTC


README

本包是从 ArranJacques/laravel-aws-cognito-auth 分支出来的。

这是一个简单的 Laravel 5 认证包,用于通过 AWS API 网关辅助函数在 Amazon Cognito 用户池中验证用户,支持组和角色。

此包与 Laravel 的原生认证系统兼容,允许验证已在 Amazon Cognito 用户池中注册的用户,获取用户组和角色,并且仅对首次登录的用户更改密码。它不提供用户管理功能,例如将用户注册到用户池、密码重置等。

内容

安装和设置

此包使用了 aws-sdk-php-laravel 包。除了设置和配置此包外,您还需要配置 aws-sdk-php-laravel 以使认证生效。下面提供了如何进行此操作的说明。如果您已经安装、设置并配置了 aws-sdk-php-laravel,则可以跳过下面提到的部分。

安装

pallant/laravel-aws-cognito-auth 添加到 composer.json 并运行 composer update 以获取最新版本

"shady-amir/laravel-aws-cognito-auth": "~1.2.2"

或使用 composer require

composer require shady-amir/laravel-aws-cognito-auth

将服务提供者和 aws-sdk-php-laravel 服务提供者添加到 config/app.php 文件中的 providers 数组。

'providers' => [
    ...
    Aws\Laravel\AwsServiceProvider::class,
    Pallant\LaravelAwsCognitoAuth\ServiceProvider::class,
    ...
]

打开 app/Http/Kernel.php 并将默认的 \Illuminate\Session\Middleware\AuthenticateSession::class 中间件替换为 \Pallant\LaravelAwsCognitoAuth\AuthenticateSession::class

protected $middlewareGroups = [
    'web' => [
        ...
        \Pallant\LaravelAwsCognitoAuth\AuthenticateSession::class,
        ...
    ],
];

通过运行以下命令将配置文件以及 aws-sdk-php-laravel 配置文件发布到您的 config 目录:

php artisan vendor:publish --provider="Pallant\LaravelAwsCognitoAuth\ServiceProvider"

php artisan vendor:publish --provider="Aws\Laravel\AwsServiceProvider"

配置

打开 config/auth.php 并将默认保护者的驱动设置为 aws-cognito。默认情况下,默认保护者是 web,因此您的 config/auth.php 应该看起来像这样:

'defaults' => [
    'guard' => 'web',
    'passwords' => 'users',
],

...

'guards' => [
    'web' => [
        'driver' => 'aws-cognito',
        'provider' => 'users',
    ],
]

打开 config/aws-cognito-auth.php 并添加您的 AWS Cognito 用户池的 id 和用户池应用的 client-id

'pool-id' => '<xxx-xxxxx>',

...

'apps' => [
    'default' => [
        'client-id' => '<xxxxxxxxxx>',
        'refresh-token-expiration' => 30,
    ],
]

在为您的用户池创建应用时,默认的刷新令牌过期时间为 30 天。如果您已为您的应用设置了不同的过期时间,请确保相应地更新配置文件中的 refresh-token-expiration 值。

'apps' => [
    'default' => [
        'client-id' => '<xxxxxxxxxx>',
        'refresh-token-expiration' => <num-of-days>,
    ],
]

打开 config/aws.php 文件并将 region 值设置为您的用户池所在的区域。当使用 php artisan vendor:publish --provider="Aws\Laravel\AwsServiceProvider" 命令创建默认的 config/aws.php 文件时,不包括 IAM 凭据属性,因此您需要手动添加它们。将以下内容添加到 config/aws.php 文件中,其中 key 是 IAM 用户访问密钥 ID,而 secret 是相应的密钥:

'credentials' => [
    'key' => <xxxxxxxxxx>,
    'secret' => <xxxxxxxxxx>,
]

您的最终 config/aws.php 应该看起来像这样

'credentials' => [
    'key' => <xxxxxxxxxx>,
    'secret' => <xxxxxxxxxx>,
],
'region' => <xx-xxxx-x>,
'version' => 'latest',
'ua_append' => [
    'L5MOD/' . AwsServiceProvider::VERSION,
],

用户表

Cognito 不被视为“用户数据库”,仅用于授权用户。只有当用户已存在于应用的数据库中时,才会向 Cognito 发送请求。这意味着您仍然需要一个包含您要验证的用户信息的 users 表。至少这个表需要一个 idemailremember_token 字段。

在 Cognito 中,每个用户都有一个 username。当使用 Cognito 进行验证时,此包需要匹配用户的 Cognito 用户名的用户属性之一。默认情况下,它使用用户的 email 属性。

如果您想使用不同的属性来存储用户的 Cognito 用户名,可以在您的 users 表中添加一个新字段,例如 cognito_username,然后在 config/aws-cognito-auth.php 文件中将 username-attribute 设置为该字段的名称。

注意:如果用户不存在,它将在本地数据库中创建用户。

用法

一旦安装和配置完成,身份验证的工作方式与 Laravel 内置的身份验证相同。有关详细信息,请参阅 Laravel 的文档

认证

验证

Auth::attempt([
    'email' => 'xxxxx@xxxxx.xx',
    'password' => 'xxxxxxxxxx',
]);

验证并记住

Auth::attempt([
    'email' => 'xxxxx@xxxxx.xx',
    'password' => 'xxxxxxxxxx',
], true);

更改密码(挑战名称 = NEW_PASSWORD_REQUIRED)

Auth::confirmPassword([
    'email' => 'xxxxx@xxxxx.xx',
    'password' => 'xxxxxxxxxx',
    'session' => 'xxxxxxxxxx',
]);

获取已验证用户

Auth::user();

登出

Auth::logout();

除了默认功能外,还提供了一些额外的方法来访问用户的 Cognito 访问令牌、id 令牌等。

Auth::getCognitoAccessToken();
Auth::getCognitoIdToken();
Auth::getCognitoRefreshToken();
Auth::getCognitoTokensExpiryTime();
Auth::getCognitoRefreshTokenExpiryTime();
Auth::getCognitoAccessRoles();
Auth::getCognitoAccessGroups();
Auth::hasCognitoAccessRole($role)
Auth::hasCognitoAccessGroup($group)

AWS API 网关

示例

use Pallant\LaravelAwsCognitoAuth\Utilities\AwsSecureRequest;


$region = env('AWS_GETWAY_API_REGION');
$version = env('AWS_GETWAY_API_VERSION');
$IdentityPoolId = env('AWS_GETWAY_API_IDENTITY_POOL_ID');
$Logins = env('AWS_GETWAY_API_LOGINS');
$awsSecureRequest = new AwsSecureRequest($region, $version, $IdentityPoolId, $Logins);

$host = 'AWS_HOST_API_GATEWAY_WITHOUT_HTTPS';
$uri = 'URI_TO_API_CALL';
$QueryString = '';
$httpRequestMethod = 'GET';
$postData = [];
$awsService = 'execute-api'
$userIdToken = 'idToken'; // Auth::getCognitoIdToken();
$debug = TRUE;

$result = $this->awsSecureRequest->SignatureAndCallAPI($host, $uri, $awsService, $httpRequestMethod, $QueryString, $postData, $userIdToken,$debug);

处理失败的认证

AWS Cognito 可能由于多种原因而无法验证,从简单地输入错误的凭据到需要额外的检查或操作才能成功验证用户。

因此,在包内提供了几个选项,用于指定如何处理失败的尝试。

方法

您可以通过在调用 Auth::attempt()Auth::validate() 方法时传递额外的 $errorHandler 参数来指定如何处理失败的尝试。

Auth::attempt(array $credentials, [bool $remember], [$errorHandler]);

Auth::validate(array $credentials, [$errorHandler]);
不处理错误

如果没有传递 $errorHandler,则所有失败的验证尝试都将由内部处理和抑制,并且 Auth::attempt()Auth::validate() 方法将简单地返回 truefalse,以表示验证尝试是否成功。

抛出异常

要将 Auth::attempt()Auth::validate() 方法抛出异常,请将 AWS_COGNITO_AUTH_THROW_EXCEPTION 作为 $errorHandler 参数传递。

Auth::attempt([
    'email' => 'xxxxx@xxxxx.xx',
    'password' => 'xxxxxxxxxx',
], false, AWS_COGNITO_AUTH_THROW_EXCEPTION);

Auth::validate([
    'email' => 'xxxxx@xxxxx.xx',
    'password' => 'xxxxxxxxxx',
], AWS_COGNITO_AUTH_THROW_EXCEPTION);

如果验证失败,则将抛出 \Pallant\LaravelAwsCognitoAuth\AuthAttemptException 异常,可以通过调用异常的 getResponse() 方法来访问底层错误。有关 AuthAttemptException 的说明。

try {
    Auth::attempt([
        'email' => 'xxxxx@xxxxx.xx',
        'password' => 'xxxxxxxxxx',
    ], false, AWS_COGNITO_AUTH_THROW_EXCEPTION);
} catch (\Pallant\LaravelAwsCognitoAuth\AuthAttemptException $e) {
    $response = $e->getResponse();
    // Handle error...
}
返回尝试实例

要使 Auth::attempt()Auth::validate() 方法返回尝试对象,请将 AWS_COGNITO_AUTH_RETURN_ATTEMPT 作为 $errorHandler 参数传递。

Auth::attempt([
    'email' => 'xxxxx@xxxxx.xx',
    'password' => 'xxxxxxxxxx',
], false, AWS_COGNITO_AUTH_RETURN_ATTEMPT);

Auth::validate([
    'email' => 'xxxxx@xxxxx.xx',
    'password' => 'xxxxxxxxxx',
], AWS_COGNITO_AUTH_RETURN_ATTEMPT);

当使用 AWS_COGNITO_AUTH_RETURN_ATTEMPT 时,两个方法都将返回 \Pallant\LaravelAwsCognitoAuth\AuthAttempt 的实例,可以用来检查验证尝试是否成功。

$attempt = Auth::attempt([
    'email' => 'xxxxx@xxxxx.xx',
    'password' => 'xxxxxxxxxx',
], false, AWS_COGNITO_AUTH_RETURN_ATTEMPT);

if ($attempt->successful()) {
    // Do something...
} else {
    $response = $attempt->getResponse();
    // Handle error...
}

对于失败的验证尝试,可以使用尝试实例的 getResponse() 方法来访问底层错误。此方法将返回一个包含不同值的数组,这些值取决于失败尝试的原因。

在 AWS Cognito API 抛出异常的事件中,例如使用无效凭据时,返回的数组将包含原始异常。

[
    'exception' => CognitoIdentityProviderException {...},
]

在 AWS Cognito API 由于其他原因无法验证的事件中,例如必须通过挑战时,返回的数组将包含错误详情。

[
    'ChallengeName' => 'NEW_PASSWORD_REQUIRED',
    'Session' => '...',
    'ChallengeParameters' => [...],
]
使用闭包

要通过闭包处理失败的验证尝试,请将其作为 Auth::attempt()Auth::validate() 方法的 $errorHandler 参数传递。

Auth::attempt([
    'email' => 'xxxxx@xxxxx.xx',
    'password' => 'xxxxxxxxxx',
], false, function (\Pallant\LaravelAwsCognitoAuth\AuthAttemptException $e) {
    $response = $e->getResponse();
    // Handle error...
});

Auth::validate([
    'email' => 'xxxxx@xxxxx.xx',
    'password' => 'xxxxxxxxxx',
], function (\Pallant\LaravelAwsCognitoAuth\AuthAttemptException $e) {
    $response = $e->getResponse();
    // Handle error...
};

如果认证失败,则将执行关闭操作,并将一个 \Pallant\LaravelAwsCognitoAuth\AuthAttemptException 实例传递给它,可以使用该异常的 getResponse() 方法来访问底层错误。关于 AuthAttemptException

使用自定义类

要使用自定义类处理失败的认证尝试,请将类名作为 Auth::attempt()Auth::validate() 方法的 $errorHandler 参数传递。

Auth::attempt([
    'email' => 'xxxxx@xxxxx.xx',
    'password' => 'xxxxxxxxxx',
], false, \App\MyCustomErrorHandler::class);

Auth::validate([
    'email' => 'xxxxx@xxxxx.xx',
    'password' => 'xxxxxxxxxx',
], \App\MyCustomErrorHandler::class);

错误处理类应该有一个 handle() 方法,当认证尝试失败时,将调用此方法。该方法将传递一个 \Pallant\LaravelAwsCognitoAuth\AuthAttemptException 实例,可以使用该异常的 getResponse() 方法来访问底层错误。关于 AuthAttemptException

<?php

namespace App;

use Pallant\LaravelAwsCognitoAuth\AuthAttemptException;

class MyCustomErrorHandler
{
    public function handle(AuthAttemptException $e)
    {
        $response = $e->getResponse();
        // Handle error...
    }
}

默认错误处理器

除了在行内定义错误处理器外,还可以在 config/aws-cognito-auth.php 文件中定义默认的错误处理器。可以使用上述详细说明的错误处理方法。当使用 AWS_COGNITO_AUTH_THROW_EXCEPTIONAWS_COGNITO_AUTH_RETURN_ATTEMPT 设置为字符串时,请勿使用常量。

抛出异常

'errors' => [
    'handler' => 'AWS_COGNITO_AUTH_THROW_EXCEPTION',
],

返回尝试

'errors' => [
    'handler' => 'AWS_COGNITO_AUTH_RETURN_ATTEMPT',
],

使用闭包

'errors' => [
    'handler' => function (\Pallant\LaravelAwsCognitoAuth\AuthAttemptException $e) {
        $e->getResponse();
        // Do something...
    },
],

使用自定义类

'errors' => [
    'handler' => \App\MyCustomErrorHandler::class,
],

关于 AuthAttemptException

使用 AWS_COGNITO_AUTH_THROW_EXCEPTION 错误处理器时,将抛出 \Pallant\LaravelAwsCognitoAuth\AuthAttemptException 异常;使用错误处理的 Clousre 方法时,将作为参数传递给闭包。

异常的 getResponse() 方法将返回一个包含不同值的数组,这些值取决于失败尝试的原因。

在 AWS Cognito API 抛出异常的事件中,例如使用无效凭据时,返回的数组将包含原始异常。

[
    'exception' => CognitoIdentityProviderException {...},
]

在 AWS Cognito API 由于某些其他原因(例如,必须通过挑战)未能认证的情况下,返回的数组将包含错误详情。

[
    'ChallengeName' => 'NEW_PASSWORD_REQUIRED',
    'Session' => '...',
    'ChallengeParameters' => [...],
]