zozlak / auth
非常简单且灵活的认证框架
2.0.1
2024-01-08 16:49 UTC
Requires
- php: >=7.0
- guzzlehttp/guzzle: ^7
Requires (Dev)
- phpstan/phpstan: ^1.3
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
请记住,Guest
、GoogleToken
和TrustedHeaders
不支持广告。
HTTP摘要方法
HTTP摘要难以与其他任何认证方法结合使用。与任何其他方法不同,HTTP摘要必须在客户端请求之前向客户端广告,以便它可以准备有效的凭证。一旦广告,所有GUI客户端(尤其是网络浏览器)将不断要求用户提供登录名和密码,直到提供有效的凭证,这使得无法使用任何其他认证方法。
针对此问题的(较差的)解决方案包括
- 将HTTP摘要放在认证链的末尾,允许先检查其他任何认证方法。
- 将HTTP摘要提供者的广告设置为
ADVERTISE_ONCE
。在这种情况下,它只有在客户端在其请求中没有提供HTTP摘要凭证时才会广告,并且如果提供了凭证(无论它们是好是坏),则HTTP摘要方法不会再次广告。这允许解决HTTP摘要之后的认证提供者,但代价是用户只能输入一次正确的登录名和密码。