Khi Symfony2 xử lý yêu cầu, nó khớp với mẫu url với mỗi tường lửa được xác định trong app/config/security.yml
. Khi mẫu url khớp với mẫu tường lửa Symfony2 tạo một số đối tượng nghe và gọi phương thức handle
của các đối tượng đó. Nếu bất kỳ trình lắng nghe nào trả về đối tượng Response
thì ngắt vòng lặp và Symfony2 sẽ trả về kết quả. Phần xác thực được thực hiện trong trình lắng nghe xác thực. Chúng được tạo từ cấu hình được xác định trong tường lửa phù hợp, ví dụ: form_login
, http_basic
v.v. Nếu người dùng không được xác thực thì người nghe được xác thực tạo đối tượng RedirectResponse
để chuyển hướng người dùng đến trang đăng nhập. Trong trường hợp của bạn, bạn có thể gian lận bằng cách tạo trình xử lý xác thực tùy chỉnh và thêm nó vào tường lửa trang được bảo mật của mình. Triển khai mẫu sẽ được sau,
Tạo một lớp Token
,
namespace Your\Namespace;
use Symfony\Component\Security\Core\Authentication\Token\AbstractToken;
class MyToken extends AbstractToken
{
public function __construct(array $roles = array())
{
parent::__construct($roles);
}
public function getCredentials()
{
return '';
}
}
Tạo một lớp mà thực hiện AuthenticationProviderInterface
. Đối với người nghe form_login
, người nghe sẽ xác thực với số UserProvider
đã cho. Trong trường hợp này nó sẽ không làm gì cả.
namespace Your\Namespace;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Authentication\Provider\AuthenticationProviderInterface;
use Acme\BaseBundle\Firewall\MyToken;
class MyAuthProvider implements AuthenticationProviderInterface
{
public function authenticate(TokenInterface $token)
{
if (!$this->supports($token)) {
return null;
}
throw new \Exception('you should not get here');
}
public function supports(TokenInterface $token)
{
return $token instanceof MyToken;
}
Tạo lớp điểm nhập. Người nghe sẽ tạo một số RedirectResponse
từ lớp này.
namespace Your\Namespace;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Symfony\Component\Security\Http\EntryPoint\AuthenticationEntryPointInterface;
use Symfony\Component\Security\Http\HttpUtils;
class MyAuthenticationEntryPoint implements AuthenticationEntryPointInterface
{
private $httpUtils;
private $redirectPath;
public function __construct(HttpUtils $httpUtils, $redirectPath)
{
$this->httpUtils = $httpUtils;
$this->redirectPath = $redirectPath;
}
/**
* {@inheritdoc}
*/
public function start(Request $request, AuthenticationException $authException = null)
{
//redirect action goes here
return $this->httpUtils->createRedirectResponse($request, $this->redirectPath);
}
Tạo lớp người nghe. Ở đây bạn sẽ thực hiện logic chuyển hướng của bạn.
namespace Your\Namespace;
use Symfony\Component\Security\Http\Firewall\ListenerInterface;
use Symfony\Component\HttpKernel\Event\GetResponseEvent;
use Symfony\Component\Security\Core\SecurityContextInterface;
use Symfony\Component\Security\Http\EntryPoint\AuthenticationEntryPointInterface;
class MyAuthenticationListener implements ListenerInterface
{
private $securityContext;
private $authenticationEntryPoint;
public function __construct(SecurityContextInterface $securityContext, AuthenticationEntryPointInterface $authenticationEntryPoint)
{
$this->securityContext = $securityContext;
$this->authenticationEntryPoint = $authenticationEntryPoint;
}
public function handle(GetResponseEvent $event)
{
$token = $this->securityContext->getToken();
$request = $event->getRequest();
if($token === null){
return;
}
//add your logic
$redirect = // boolean value based on your logic
if($token->isAuthenticated() && $redirect){
$response = $this->authenticationEntryPoint->start($request);
$event->setResponse($response);
return;
}
}
}
Tạo dịch vụ.
<?xml version="1.0" ?>
<container xmlns="http://symfony.com/schema/dic/services"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd">
<services>
<service id="my_firewall.security.authentication.listener"
class="Your\Namespace\MyAuthenticationListener"
parent="security.authentication.listener.abstract"
abstract="true">
<argument type="service" id="security.context" />
<argument /> <!-- Entry Point -->
</service>
<service id="my_firewall.entry_point" class="Your\Namespace\MyAuthenticationEntryPoint" public="false" ></service>
<service id="my_firewall.auth_provider" class="Your\Namespace\MyAuthProvider" public="false"></service>
</services>
</container>
Đăng ký người nghe. Tạo thư mục có tên Security/Factory
trong nhóm của bạn DependencyInjection
thư mục. Sau đó tạo lớp nhà máy.
namespace Your\Bundle\DependencyInjection\Security\Factory;
use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\DependencyInjection\DefinitionDecorator;
use Symfony\Component\DependencyInjection\Definition;
use Symfony\Bundle\SecurityBundle\DependencyInjection\Security\Factory\SecurityFactoryInterface;
use Symfony\Component\Config\Definition\Builder\NodeDefinition;
class MyFirewallFactory implements SecurityFactoryInterface
{
public function create(ContainerBuilder $container, $id, $config, $userProvider, $defaultEntryPoint)
{
$provider = 'my_firewall.auth_provider.'.$id;
$container->setDefinition($provider, new DefinitionDecorator('my_firewall.auth_provider'));
// entry point
$entryPointId = $this->createEntryPoint($container, $id, $config, $defaultEntryPoint);
// listener
$listenerId = 'my_firewall.security.authentication.listener'.$id;
$listener = $container->setDefinition($listenerId, new DefinitionDecorator('my_firewall.security.authentication.listener'));
$listener->replaceArgument(1, new Reference($entryPointId));
return array($provider, $listenerId, $entryPointId);
}
public function getPosition()
{
return 'pre_auth';
}
public function getKey()
{
return 'my_firewall'; //the listener name
}
protected function getListenerId()
{
return 'my_firewall.security.authentication.listener';
}
public function addConfiguration(NodeDefinition $node)
{
$node
->children()
->scalarNode('redirect_path')->end()
->end()
;
}
protected function createEntryPoint($container, $id, $config, $defaultEntryPointId)
{
$entryPointId = 'my_firewall.entry_point'.$id;
$container
->setDefinition($entryPointId, new DefinitionDecorator('my_firewall.entry_point'))
->addArgument(new Reference('security.http_utils'))
->addArgument($config['redirect_path'])
;
return $entryPointId;
}
}
Sau đó, trong NamespaceBundle.php
của thư mục gói, hãy thêm mã sau đây.
public function build(ContainerBuilder $builder){
parent::build($builder);
$extension = $builder->getExtension('security');
$extension->addSecurityListenerFactory(new Security\Factory\MyFirewallFactory());
}
Trình nghe xác thực được tạo, phew :). Bây giờ trong số app/config/security.yml
của bạn làm theo.
api_area:
pattern: ^/secured/
provider: fos_userbundle
form_login:
check_path: /login_check
login_path: /login
csrf_provider: form.csrf_provider
my_firewall:
redirect_path: /beta
logout: true
anonymous: true
Tôi không chắc bạn đang cố gắng đạt được điều gì. Khi người dùng nhập URL (hoặc đang được chuyển hướng đến) action ** hành động đó được bảo mật hoặc không được bảo mật **. Bộ điều khiển không thể có nhiều hành động (bảo mật và không được bảo mật) với cùng tên, vì rõ ràng là tên phương thức. Tuy nhiên, bạn có thể yêu cầu SecureContext nếu người dùng truy cập có vai trò tương ứng và sau đó làm điều gì đó với yêu cầu (ví dụ: chuyển tiếp, chuyển hướng) –