Блокировка доступа через HTTP аутентификацию с помощью Zend Framework 2
Я пытаюсь реализовать аутентификацию на основе HTTP через ZendAuthenticationAdapterHttp
, как описано в документации ZF2 об адаптере аутентификации HTTP.
Я хочу блокировать каждый входящий запрос до тех пор, пока агент пользователя не будет аутентифицирован, однако я не уверен в том, как реализовать это в моем модуле.
Как бы я настроил свое приложение ZendMvc, чтобы запретить доступ к моим контроллерам?
3 ответа:
То, что вы ищете, вероятно, слушатель, прикрепленный к
Zend\Mvc\MvcEvent::EVENT_DISPATCH
событие вашей заявки.Чтобы заблокировать доступ к любому действию через адаптер аутентификации, выполните следующие действия. Прежде всего, определите фабрику, которая отвечает за производство вашего адаптера аутентификации:
namespace MyApp\ServiceFactory; use Zend\ServiceManager\FactoryInterface; use Zend\ServiceManager\ServiceLocatorInterface; use Zend\Authentication\Adapter\Http as HttpAdapter; use Zend\Authentication\Adapter\Http\FileResolver; class AuthenticationAdapterFactory implements FactoryInterface { public function createService(ServiceLocatorInterface $serviceLocator) { $config = $serviceLocator->get('Config'); $authConfig = $config['my_app']['auth_adapter']; $authAdapter = new HttpAdapter($authConfig['config']); $basicResolver = new FileResolver(); $digestResolver = new FileResolver(); $basicResolver->setFile($authConfig['basic_passwd_file']); $digestResolver->setFile($authConfig['digest_passwd_file']); $adapter->setBasicResolver($basicResolver); $adapter->setDigestResolver($digestResolver); return $adapter; } }
Эта фабрика в основном даст вам настроенный адаптер auth и абстрагирует его логику создания экземпляров.
Давайте продолжим и приложим прослушиватель события
dispatch
нашего приложения, чтобы мы могли заблокировать любой запрос с недопустимыми заголовками аутентификации:namespace MyApp; use Zend\ModuleManager\Feature\ConfigProviderInterface; use Zend\ModuleManager\Feature\BootstrapListenerInterface; use Zend\EventManager\EventInterface; use Zend\Mvc\MvcEvent; use Zend\Http\Request as HttpRequest; use Zend\Http\Response as HttpResponse; class MyModule implements ConfigProviderInterface, BootstrapListenerInterface { public function getConfig() { // moved out for readability on SO, since config is pretty short anyway return require __DIR__ . '/config/module.config.php'; } public function onBootstrap(EventInterface $event) { /* @var $application \Zend\Mvc\ApplicationInterface */ $application = $event->getTarget(); $serviceManager = $application->getServiceManager(); // delaying instantiation of everything to the latest possible moment $application ->getEventManager() ->attach(function (MvcEvent $event) use ($serviceManager) { $request = $event->getRequest(); $response = $event->getResponse(); if ( ! ( $request instanceof HttpRequest && $response instanceof HttpResponse )) { return; // we're not in HTTP context - CLI application? } /* @var $authAdapter \Zend\Authentication\Adapter\Http */ $authAdapter = $serviceManager->get('MyApp\AuthenticationAdapter'); $authAdapter->setRequest($request); $authAdapter->setResponse($response); $result = $adapter->authenticate(); if ($result->isValid()) { return; // everything OK } $response->setBody('Access denied'); $response->setStatusCode(HttpResponse::STATUS_CODE_401); $event->setResult($response); // short-circuit to application end return false; // stop event propagation }, MvcEvent::EVENT_DISPATCH); } }
, а затем конфигурация модуля по умолчанию, которая в этом случае была перемещена в
MyModule/config/module.config.php
:Это суть того, как вы можете это сделать.return array( 'my_app' => array( 'auth_adapter' => array( 'config' => array( 'accept_schemes' => 'basic digest', 'realm' => 'MyApp Site', 'digest_domains' => '/my_app /my_site', 'nonce_timeout' => 3600, ), 'basic_passwd_file' => __DIR__ . '/dummy/basic.txt', 'digest_passwd_file' => __DIR__ . '/dummy/digest.txt', ), ), 'service_manager' => array( 'factories' => array( 'MyApp\AuthenticationAdapter' => 'MyApp\ServiceFactory\AuthenticationAdapterFactory', ), ), );
Очевидно, что вам нужно разместить что - то вроде файла
my_app.auth.local.php
в вашем каталогеconfig/autoload/
с настройками, специфичными для вашей текущей среды (обратите внимание, что этот файл не должен быть привязан к вашей SCM):<?php return array( 'my_app' => array( 'auth_adapter' => array( 'basic_passwd_file' => __DIR__ . '/real/basic_passwd.txt', 'digest_passwd_file' => __DIR__ . '/real/digest_passwd.txt', ), ), );
В конечном счете, если вы также хотите иметь лучший тестируемый код, вы можете переместить прослушиватель, определенный как закрытие, в собственный класс, реализующий
Zend\EventManager\ListenerAggregateInterface
.Вы можете достичь тех же результатов, используя
ZfcUser
поддержанный aZend\Authentication\Adapter\Http
, в сочетании сBjyAuthorize
, который обрабатывает логику слушателя на несанкционированных действиях.
Ответ @ocramius - это принять ответ , но вы забыли описать, как писать два файла
basic_password.txt
иdigest_passwd.txt
Согласно Zend 2 официальный документ о базовой HTTP аутентификации :
basic_passwd.txt
файл содержит имя пользователя, область (та же область в вашей конфигурации) и простой пароль -><username>:<realm>:<credentials>\n
digest_passwd.txt
файл содержит имя пользователя, область (та же область в вашей конфигурации) и хэширование пароля с помощью MD5-хэша - ><username>:<realm>:<credentials hashed>\n
Пример:
Если
basic_passwd.txt
файл:user:MyApp Site:password\n
Затем
digest_passwd.txt
файл:user:MyApp Site:5f4dcc3b5aa765d61d8327deb882cf99\n
В качестве альтернативы вы можете использовать Apache Resolver для HTTP-адаптера
use Zend\Authentication\Adapter\Http\ApacheResolver; $path = 'data/htpasswd'; // Inject at instantiation: $resolver = new ApacheResolver($path); // Or afterwards: $resolver = new ApacheResolver(); $resolver->setFile($path);
Согласно https://zendframework.github.io/zend-authentication/adapter/http/#resolvers