zozlak/auth

非常简单且灵活的认证框架

2.0.1 2024-01-08 16:49 UTC

This package is auto-updated.

Last update: 2024-09-08 18:10:57 UTC


README

一个简单且灵活的认证库,用于对不同提供者进行认证。

当前支持的授权提供者

  • HTTP基本认证
  • HTTP摘要认证
  • 用户登录和从HTTP头中获取数据(例如当由Shibboleth设置时)
  • Google访问令牌
  • 固定数据(例如备用访客用户)

当前支持的用户数据库后端

  • PDO

用法

一个简单的示例,尝试使用Google进行认证,然后使用HTTP基本认证,最后使用固定的zzz用户作为备用。

namespace zozlak\auth;
require '/vendor/autoload.php';
$db = new usersDb\PdoDb('sqlite::memory:');

// init users
$db->putUser('aaa', authMethod\HttpBasic::pswdData('1234'));
$db->putUser('bbb', authMethod\HttpBasic::pswdData('1234'));

// create auth controller and add auth methods
// (comment/uncomment $ctl->addMethod() lines to test different combinations)
$ctl   = new AuthController($db);

$header = new TrustedHeader('HTTP_EPPN');
$ctl->addMethod($header);

$token = new GoogleToken(filter_input(INPUT_GET, 'token') ?? '');
$ctl->addMethod($token);

$shb = new Shibboleth('HTTP_EPPN', '', [], 'https://my.app/Shibboleth.sso/Login', 'https://my.app/url');
//$ctl->addMethod($shb, AuthController::ADVERTISE_ONCE);

$googleAppCfg = [
    'client_id' => 'appid.apps.googleusercontent.com',
    'client_secret' => 'appsecret',
    'redirect_uris' => ['https://my.app/url']
];
$googleAuthCfg = ['access_type' => 'offline', 'refresh_time' => 600];
$google = new Google(filter_input(INPUT_GET, 'token') ?? '', $googleAppCfg, $googleAuthCfg);
//$ctl->addMethod($google, AuthController::ADVERTISE_ONCE);

$basic = new HttpBasic('my realm');
$ctl->addMethod($basic, AuthController::ADVERTISE_ONCE);

$digest = new HttpDigest('realm');
//$ctl->addMethod($digest, AuthController::ADVERTISE_ONCE);

$guest = new Guest('zzz');
$ctl->addMethod($guest);

// try to authenticate
if ($ctl->authenticate()) {
    print_r([$ctl->getUserName(), $ctl->getUserData()]);
} else {
    // if not authenticated, advertise available method
    $ctl->advertise();
    header('HTTP/1.1 401 Unauthorized');
    echo "Authentication failed\n";
}

组合多种认证方法

链式组合多种认证方法很容易,直到只需检查客户端请求中提供的凭证。

问题开始于请求中没有(有效)凭证,并且我们希望显式要求用户包含它们。问题是大多数情况下我们只能一次广告一个认证方法**。这是因为不同的认证方法使用冲突的广告机制,例如。

  • 所有OAuth2(Google等)和SAML(Shibboleth)方法都使用Location头将用户重定向到登录页面,并且我们不能在一个响应中返回多个不同位置的多个重定向
  • 响应中存在HTTP基本或HTTP摘要认证头将迫使所有GUI客户端提示用户输入用户名和密码,并跳过响应的其余部分

以下方式提供对广告认证方法的控制

  • 您可以为链中的每个方法分配三种广告级别之一
    • AuthMethod::ADVERTISE_NONE认证方法永远不会广告
    • AuthMethod::ADVERTISE_ONCE认证方法只有在请求没有为此方法提供凭证时才会广告(如果请求为此方法提供了错误的凭证,则该方法不会再次广告)
    • AuthMethod::ADVERTISE_ALWAYS认证方法始终广告
  • 当您调用AutController::advertise()方法时,第一个满足其广告条件的认证方法会被广告。

您在将方法添加到认证链时分配广告级别,使用AutController::addMethod(AuthMethodInterface $method, int $advertise)方法的第二个参数。默认为AuthMethod::ADVERTISE_NONE

请记住,GuestGoogleTokenTrustedHeaders不支持广告。

HTTP摘要方法

HTTP摘要难以与其他任何认证方法结合使用。与任何其他方法不同,HTTP摘要必须在客户端请求之前向客户端广告,以便它可以准备有效的凭证。一旦广告,所有GUI客户端(尤其是网络浏览器)将不断要求用户提供登录名和密码,直到提供有效的凭证,这使得无法使用任何其他认证方法。

针对此问题的(较差的)解决方案包括

  • 将HTTP摘要放在认证链的末尾,允许先检查其他任何认证方法。
  • 将HTTP摘要提供者的广告设置为ADVERTISE_ONCE。在这种情况下,它只有在客户端在其请求中没有提供HTTP摘要凭证时才会广告,并且如果提供了凭证(无论它们是好是坏),则HTTP摘要方法不会再次广告。这允许解决HTTP摘要之后的认证提供者,但代价是用户只能输入一次正确的登录名和密码。