Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/symfony/6.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/google-maps/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Symfony 如何在自定义安全包中发生身份验证错误时重定向到注销页面_Symfony - Fatal编程技术网

Symfony 如何在自定义安全包中发生身份验证错误时重定向到注销页面

Symfony 如何在自定义安全包中发生身份验证错误时重定向到注销页面,symfony,Symfony,我正在尝试创建一个自定义安全包 我可以设法让一些东西工作(长时间和努力:-) 除了当我在某个地方出现身份验证错误时,我希望被重新路由到 “注销”页面,而不是登录页面 我认为如果抛出异常,以这种方式更改security.yml将发送到失败路径 security: firewalls: logout: pattern: ^/logout$ security: false secured_area:

我正在尝试创建一个自定义安全包

我可以设法让一些东西工作(长时间和努力:-)

除了当我在某个地方出现身份验证错误时,我希望被重新路由到 “注销”页面,而不是登录页面

我认为如果抛出异常,以这种方式更改security.yml将发送到失败路径

security:
    firewalls:
        logout:
            pattern:  ^/logout$
            security: false

        secured_area:
            pattern: ^/
            my_user_factory: true
            form_login:
                login_path: /login
                check_path: /login_check
                failure_path: /logout
由于我的基本代码一直在工作(没有真正的控件),我添加了一个异常抛出来测试身份验证错误

class AuthProvider implements AuthenticationProviderInterface
{
//...
    public function authenticate(TokenInterface $token)
    {
        throw new BadCredentialsException('Bad credentials :)');
    }
//...
但我回到了登录页面

以下是跟踪:

// I arrive on the site
UserFactory.getPosition
UserFactory.getKey
UserFactory.getKey
UserFactory.create
CnamtsSecurityExtension.load
Configuration.getConfigTreeBuilder
AcmeSecurityExtension.load
Configuration.getConfigTreeBuilder
AuthProvider.__construct
AuthListener.__construct
AuthProvider.__construct

// Let's login
SecurityController.loginAction
AuthProvider.__construct
AuthListener.__construct
AuthListener.attemptAuthentication
UserToken.__construct
AuthProvider.supports
AuthProvider.authenticate
// The exception is thrown

UserToken.serialize
UserToken.unserialize
UserToken.serialize
AuthProvider.__construct
SecurityController.loginAction
// Back to the login page. I'd like to be on the logout one.
这是全部代码。如果删除“抛出新的BadCredentialsException('Bad credentials:)”;”行 它应该会起作用

束树:

|~src/
| |~Acme/
| | `~SecurityBundle/
| |   |~Controller/
| |   | |-DefaultController.php
| |   | `-SecurityController.php
| |   |~DependencyInjection/
| |   | |~Security/
| |   | | `~Factory/
| |   | |   `-UserFactory.php
| |   | |-AcmeSecurityExtension.php
| |   | `-Configuration.php
| |   |~Resources/
| |   | |~config/
| |   | | |-routing.yml
| |   | | |-security_factories.yml
| |   | | `-services.yml
| |   | `~views/
| |   |   |~Default/
| |   |   | `-index.html.twig
| |   |   | `-logout.html.twig
| |   |   `~Login/
| |   |     `-login.html.twig
| |   |~Security/
| |   | |~Authentication/
| |   | | |~Firewall/
| |   | | | `-AuthListener.php
| |   | | |~Provider/
| |   | | | `-AuthProvider.php
| |   | | `~Token/
| |   | |   `-UserToken.php
| |   | `~User/
| |   |   |-User.php
| |   |   `-UserProvider.php
| |   |+Tests/
| |   `-AcmeSecurityBundle.php
工厂:

<?php
// src/Acme/SecurityBundle/DependencyInjection/Security/Factory/UserFactory.php

namespace Acme\SecurityBundle\DependencyInjection\Security\Factory;

use Symfony\Component\DependencyInjection\ContainerBuilder;
use Symfony\Component\DependencyInjection\Reference;
use Symfony\Component\DependencyInjection\DefinitionDecorator;
use Symfony\Component\Config\Definition\Builder\NodeDefinition;
use Symfony\Bundle\SecurityBundle\DependencyInjection\Security\Factory\SecurityFactoryInterface;

class UserFactory implements SecurityFactoryInterface
{
    public function create(ContainerBuilder $container, $id, $config, $userProvider, $defaultEntryPoint)
    {
        $providerId = 'security.authentication.provider.user.'.$id;
        $container
            ->setDefinition($providerId, new DefinitionDecorator('user.security.authentication.provider'))
            ->replaceArgument(0, new Reference($userProvider))
        ;
        $listenerId = 'security.authentication.listener.user.'.$id;
        $listener = $container->setDefinition($listenerId, new DefinitionDecorator('user.security.authentication.listener'));

        return array($providerId, $listenerId, $defaultEntryPoint);
    }

    public function getPosition()
    {
        return 'pre_auth';
    }

    public function getKey()
    {
        return 'my_user_factory';
    }

    public function addConfiguration(NodeDefinition $node)
    {}
}
工厂声明

# Acme/SecurityBundle/Resources/config/security_factories.yml

services:
    security.authentication.factory.user:
        class:  Acme\SecurityBundle\DependencyInjection\Security\Factory\UserFactory
        tags:
            - { name: security.listener.factory }
服务:

# Acme/SecurityBundle/Resources/config/services.yml

services:
    user.security.authentication.provider:
        class:  Acme\SecurityBundle\Security\Authentication\Provider\AuthProvider
        arguments: ["", %kernel.cache_dir%/security/nonces]

    user.security.authentication.listener:
        class:  Acme\SecurityBundle\Security\Authentication\Firewall\AuthListener
        arguments: [@security.context, @security.authentication.manager, @security.authentication.session_strategy, @security.http_utils]
        tags:
            - { name: monolog.logger, channel: security }

    user_provider_service:
        class: Acme\SecurityBundle\Security\User\UserProvider
应用程序参数

总路线

# /app/config/routing.yml

AcmeSecurityBundle:
    resource: "@AcmeSecurityBundle/Resources/config/routing.yml"
    prefix:   /
安全

# /app/config/security.yml

security:
    factories:
        - "%kernel.root_dir%/../src/Acme/SecurityBundle/Resources/config/security_factories.yml"

    encoders:
        Symfony\Component\Security\Core\User\User: plaintext

    role_hierarchy:
        ROLE_ADMIN:       ROLE_USER
        ROLE_SUPER_ADMIN: [ROLE_USER, ROLE_ADMIN, ROLE_ALLOWED_TO_SWITCH]

    providers:
         user_provider:
             id: user_provider_service

    firewalls:
        login:
            pattern:  ^/login$
            security: false

        logout:
            pattern:  ^/logout$
            security: false

        secured_area:
            pattern: ^/
            my_user_factory: true
            form_login:
                login_path: /login
                check_path: /login_check
                failure_path: /logout


    access_control:
        #- { path: ^/login, roles: IS_AUTHENTICATED_ANONYMOUSLY, requires_channel: https }
        #- { path: ^/_internal, roles: IS_AUTHENTICATED_ANONYMOUSLY, ip: 127.0.0.1 }
控制器和模板

控制器、主页和注销

<?php
// Acme/SecurityBundle/Controller/DefaultController.php

namespace Acme\SecurityBundle\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\Controller;


class DefaultController extends Controller
{

    public function indexAction()
    {
        return $this->render('AcmeSecurityBundle:Default:index.html.twig', 
                  array('parametres' => print_r($this->container->getParameterBag()->all(), true),
                        'request' => print_r($this->getRequest(),true)));
    }

    public function logoutAction()
    {
        $this->get('security.context')->setToken(null);
        $this->getRequest()->getSession()->invalidate();

        return $this->render('CnamtsSecurityBundle:Default:logout.html.twig', 
                  array('parametres' => print_r($this->container->getParameterBag()->all(), true),
                    'request' => print_r($this->getRequest(),true)));
    }
}

当抛出
AuthenticationException
时,Symfony调用该身份验证提供程序(如果设置了入口点)的入口点类的
start
方法,该方法最终返回对
登录路径的重定向响应。您必须发出
$token->setAuthenticated(false)在引发异常之前

要添加提供者的入口点,
UserFactory
应该扩展


有关工厂和入口点的实现,请参见和。

因此,我必须创建一个新的入口点。。。食谱中描述的失败路径是什么(如何自定义表单登录)?如果我想使用这个入口点,我必须在services.yml文件中引用它。。。类似于'security.authentication.form\u entry\u point:class:Acme\SecurityBundle\security\EntryPoint\AccessMasterEntryPoint参数:[@kernel,@security.http\u utils,%failure\u path%,“”]`您能告诉我如何引用失败路径(%failure\u path%不好…)您能否检查验证异常后代码是否到达?我想应该是这样的,因为您的
AuthListener
已经扩展了
AbstractAuthenticationInListener
。。。仅AuthenticationFailureHandlerInterface.php和AuthenticationSuccessHandlerInterface.php我仅在2.0分支(2.0.12)上。这只在2.1版本上可用吗?哦,对不起,我检查了2.1版本。他们将某些部分重构为一个新类:)。你应该检查一下。实际上是同一个代码。是的,是的。但是$this->option['failure\u path']是空的。所以我不再确定我的security.yml是否良好(代码在上面…搜索“securited_区域”)。如果是这样的话。。。我错过了一些东西。
# Acme/SecurityBundle/Resources/config/routing.yml
AcmeSecurityBundle_homepage:
    pattern:  /
    defaults: { _controller: AcmeSecurityBundle:Default:index }

AcmeSecurityBundle_logout:
    pattern:  /logout
    defaults: { _controller: AcmeSecurityBundle:Default:logout }

login:
    pattern: /login
    defaults: { _controller: AcmeSecurityBundle:Security:login }

login_check:
    pattern: /login_check
# Acme/SecurityBundle/Resources/config/security_factories.yml

services:
    security.authentication.factory.user:
        class:  Acme\SecurityBundle\DependencyInjection\Security\Factory\UserFactory
        tags:
            - { name: security.listener.factory }
# Acme/SecurityBundle/Resources/config/services.yml

services:
    user.security.authentication.provider:
        class:  Acme\SecurityBundle\Security\Authentication\Provider\AuthProvider
        arguments: ["", %kernel.cache_dir%/security/nonces]

    user.security.authentication.listener:
        class:  Acme\SecurityBundle\Security\Authentication\Firewall\AuthListener
        arguments: [@security.context, @security.authentication.manager, @security.authentication.session_strategy, @security.http_utils]
        tags:
            - { name: monolog.logger, channel: security }

    user_provider_service:
        class: Acme\SecurityBundle\Security\User\UserProvider
# /app/config/routing.yml

AcmeSecurityBundle:
    resource: "@AcmeSecurityBundle/Resources/config/routing.yml"
    prefix:   /
# /app/config/security.yml

security:
    factories:
        - "%kernel.root_dir%/../src/Acme/SecurityBundle/Resources/config/security_factories.yml"

    encoders:
        Symfony\Component\Security\Core\User\User: plaintext

    role_hierarchy:
        ROLE_ADMIN:       ROLE_USER
        ROLE_SUPER_ADMIN: [ROLE_USER, ROLE_ADMIN, ROLE_ALLOWED_TO_SWITCH]

    providers:
         user_provider:
             id: user_provider_service

    firewalls:
        login:
            pattern:  ^/login$
            security: false

        logout:
            pattern:  ^/logout$
            security: false

        secured_area:
            pattern: ^/
            my_user_factory: true
            form_login:
                login_path: /login
                check_path: /login_check
                failure_path: /logout


    access_control:
        #- { path: ^/login, roles: IS_AUTHENTICATED_ANONYMOUSLY, requires_channel: https }
        #- { path: ^/_internal, roles: IS_AUTHENTICATED_ANONYMOUSLY, ip: 127.0.0.1 }
<?php
// Acme/SecurityBundle/Controller/DefaultController.php

namespace Acme\SecurityBundle\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\Controller;


class DefaultController extends Controller
{

    public function indexAction()
    {
        return $this->render('AcmeSecurityBundle:Default:index.html.twig', 
                  array('parametres' => print_r($this->container->getParameterBag()->all(), true),
                        'request' => print_r($this->getRequest(),true)));
    }

    public function logoutAction()
    {
        $this->get('security.context')->setToken(null);
        $this->getRequest()->getSession()->invalidate();

        return $this->render('CnamtsSecurityBundle:Default:logout.html.twig', 
                  array('parametres' => print_r($this->container->getParameterBag()->all(), true),
                    'request' => print_r($this->getRequest(),true)));
    }
}
{# Acme/SecurityBundle/Resources/views/Default/index.html.twig #}
Hello ! <a href = "{{ path('AcmeSecurityBundle_logout') }}">logout</a>

<pre>
Parametres
{{ parametres }}
Request
{{ request }}
</pre>
Goodbye !

<pre>
Parametres
{{ parametres }}
Request
{{ request }}
</pre>
<?php
// src/Acme/SecurityBundle/Controller/SecurityController.php

namespace Acme\SecurityBundle\Controller;

use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\Security\Core\SecurityContext;

class SecurityController extends Controller
{
    public function loginAction()
    {
        $request = $this->getRequest();
        $session = $request->getSession();

        // get the login error if there is one
        $error = $session->get(SecurityContext::AUTHENTICATION_ERROR);
        $session->remove(SecurityContext::AUTHENTICATION_ERROR);

        return $this->render('AcmeSecurityBundle:Login:login.html.twig', array(
            // last username entered by the user
            'last_username' => $session->get(SecurityContext::LAST_USERNAME),
            'error'         => $error,
        ));
    }

}
{# Acme/SecurityBundle/Resources/views/Security/login.html.twig #}
{% if error %}
    <div>{{ error.message }}</div>
{% endif %}
<form name="loginForm" action="{{ path('login_check') }}" method="post">
    <label for="username">Username:</label>
    <input type="text" id="username" name="_username" />
    <label for="password">Password:</label>
    <input type="password" id="password" name="_password" />
    {#
        If you want to control the URL the user is redirected to on success (more details
        below)
        <input type="hidden" name="_target_path" value="/account" />
    #}
    <button type="submit">login</button>
</form>