3

我正在使用 Symfony 2.8.x 应用程序,我需要设置两个安全区域:chatadmin. 这意味着chat并且admin将使用相同的登录模板(如果可能并且我不需要为此设置不同的登录模板)。我在这里问之前用谷歌搜索过,有一些相关的东西出现了,我读了很多关于这个话题的帖子:1 , 2 , 3 , 4只是作为其中的一个例子,但我做错了,因为我不能让它正常工作。这是/app/config/security.yml看起来的样子(只是防火墙和 access_control 一段代码):

security:
    ....
    firewalls:
        admin:
            pattern: /admin/(.*)
            anonymous: ~
            form_login:
                provider: fos_userbundle
                csrf_provider: security.csrf.token_manager
                login_path: fos_user_security_login
                check_path: fos_user_security_check  
                use_forward: true                                           
                always_use_default_target_path: true
                default_target_path: /admin
                target_path_parameter: _target_path
                use_referer: true
                remember_me: true
            logout:
              target: /admin
            remember_me:
                secret:   '%secret%'
                lifetime: 604800 # 1 week in seconds
                path:     /
        chat:
            pattern: ^/chat/(.*)
            anonymous: ~
            form_login:
                provider: fos_userbundle
                csrf_provider: security.csrf.token_manager
                login_path: fos_user_security_login
                check_path: fos_user_security_check
                use_forward: true
                always_use_default_target_path: true
                default_target_path: /chat
                target_path_parameter: _target_path
                use_referer: true    
                remember_me: true
            logout: ~
            remember_me:
                secret:   '%secret%'
                lifetime: 604800 # 1 week in seconds
                path:     /

    access_control:
        - { path: ^/admin/login$, role: IS_AUTHENTICATED_ANONYMOUSLY }
        - { path: ^/admin/resetting$, role: IS_AUTHENTICATED_ANONYMOUSLY }
        - { path: ^/admin/logout$, role: IS_AUTHENTICATED_ANONYMOUSLY }

        - { path: ^/chat/login$, role: IS_AUTHENTICATED_ANONYMOUSLY }
        - { path: ^/chat/resetting$, role: IS_AUTHENTICATED_ANONYMOUSLY }
        - { path: ^/chat/logout$, role: IS_AUTHENTICATED_ANONYMOUSLY }

        - { path: ^/chat/, role: ROLE_CHATTER }
        - { path: ^/admin/, role: ROLE_ADMIN }

现在这是我的捆绑包的配置app/config/routing.yml

platform_chat:
    resource: "@PlatformChatBundle/Controller/"
    type:     annotation
    prefix:   /chat/
    options:
            expose: true

platform_admin:
    resource: "@PlatformAdminBundle/Controller/"
    type:     annotation
    prefix:   /admin/
    options:
        expose: true

因为FOSUserBundle我已经尝试了这两个(都没有成功,而且一次都没有):

#FOSUser
fos_user:
    resource: "@FOSUserBundle/Resources/config/routing/all.xml"



#FOSUser    
# this second causes doubts to me since I think I will need 
# to repeat the same routes for chat prefix but I'm not sure at all
fos_user_security:
    resource: "@FOSUserBundle/Resources/config/routing/security.xml"
    prefix: /admin

fos_user_profile:
    resource: "@FOSUserBundle/Resources/config/routing/profile.xml"
    prefix: /admin/profile

fos_user_register:
    resource: "@FOSUserBundle/Resources/config/routing/registration.xml"
    prefix: /admin/register

fos_user_resetting:
    resource: "@FOSUserBundle/Resources/config/routing/resetting.xml"
    prefix: /admin/resetting

fos_user_change_password:
    resource: "@FOSUserBundle/Resources/config/routing/change_password.xml"
    prefix: /admin/profile

我已经覆盖了登录模板app/Resources/FOSUserBundle/views/Security/login.html.twig。(如果需要来源,我可以只提供 ommit 以使帖子不再比现在长)。

当我调用 URL:http://domain.tld/app_dev.php/admin并尝试登录时,出现此错误:

找不到翻译。上下文:{“id”:“Symfony\Component\Security\Core\Exception\BadCredentialsException:凭据错误。在 /var/www/html/platform-cm/vendor/symfony/symfony/src/Symfony/Component/Security/Core /Authentication/Provider/UserAuthenticationProvider.php:90\n堆栈跟踪:\n#0

(如果需要,我可以提供完整的堆栈跟踪)

这对我来说很奇怪,但可能是由于我仔细检查了凭据而导致配置错误。

当我调用 URL:http://domain.tld/app_dev.php/chat并尝试登录时,我得到了Access Denied但这是正确的,因为我被重定向到http://domain.tld/app_dev.php/admin/. 任何人都可以给我一些关于这个配置的帮助吗?我被卡住了,因此无法前进

第二种方法

这是基于@heah 建议使用侦听器的第二种方法,但也不起作用我仍然收到相同的“错误凭据”消息并且根本无法登录。我改回了routing.yml这个:

#FOSUser
fos_user:
    resource: "@FOSUserBundle/Resources/config/routing/all.xml"

我改回了security.yml这个:

安全性:...防火墙:管理员:模式:^/匿名:〜form_login:提供者:fos_userbundle csrf_provider:security.csrf.token_manager login_path:fos_user_security_login check_path:fos_user_security_check

            # if true, forward the user to the login form instead of redirecting
            use_forward: true

            # login success redirecting options (read further below)
            always_use_default_target_path: true
            default_target_path:            /admin
            target_path_parameter:          _target_path
            use_referer: true
            remember_me:    true
        logout:
          target: /admin
        remember_me:
            secret:   '%secret%'
            lifetime: 604800 # 1 week in seconds
            path:     /

access_control:
    - { path: ^/admin/login$, role: IS_AUTHENTICATED_ANONYMOUSLY }
    - { path: ^/admin/resetting$, role: IS_AUTHENTICATED_ANONYMOUSLY }
    - { path: ^/admin/logout$, role: IS_AUTHENTICATED_ANONYMOUSLY }

    - { path: ^/chat/login$, role: IS_AUTHENTICATED_ANONYMOUSLY }
    - { path: ^/chat/resetting$, role: IS_AUTHENTICATED_ANONYMOUSLY }
    - { path: ^/chat/logout$, role: IS_AUTHENTICATED_ANONYMOUSLY }

    - { path: ^/chat/, role: ROLE_CHATTER }
    - { path: ^/admin/, role: ROLE_ADMIN }

security.interactive_login然后我按照以下建议为事件定义了一个侦听器app/config/config.yml

parameters:
    account.security_listener.class: PlatformAdminBundle\Listener\SecurityListener

然后在app/config/services.yml

services:
    account.security_listener:
        class: %account.security_listener.class%
        arguments: ['@security.context', '@session']
        tags:
            - { name: kernel.event_listener, event: security.interactive_login, method: onSecurityInteractiveLogin }

最后是类定义src/PlatformAdminBundle/Listener/SecurityListener.php

namespace PlatformAdminBundle\Listener;

use Symfony\Component\Security\Core\SecurityContextInterface;
use Symfony\Component\HttpFoundation\Session\Session;
use Symfony\Component\Security\Http\Event\InteractiveLoginEvent;

class SecurityListener
{

    public function __construct(SecurityContextInterface $security, Session $session)
    {
        $this->security = $security;
        $this->session = $session;
    }

    public function onSecurityInteractiveLogin(InteractiveLoginEvent $event)
    {
        $user = $this->security->getToken()->getUser();
        var_export($user);
    }

}

我再次遇到同样的问题,也许我做错了什么,我没有看到,但我接受任何想法。这里有什么问题?

第三种方法

我已经对我的代码进行了审查,并根据@heah 的建议对其进行了轻微更改。所以,现在security.yml如下:

access_control:
    - { path: ^/login$, role: IS_AUTHENTICATED_ANONYMOUSLY }
    - { path: ^/resetting$, role: IS_AUTHENTICATED_ANONYMOUSLY }
    - { path: ^/logout$, role: IS_AUTHENTICATED_ANONYMOUSLY }

    - { path: ^/chat/, role: ROLE_CHATTER }
    - { path: ^/admin/, role: ROLE_ADMIN }

尽管我根本没有使用它,但在 Symfony 2.6+ 中的更改services.yml基本上是修复了参数:security.context

services:
    ...
    account.security_listener:
        class: %account.security_listener.class%
        arguments: ['@security.authorization_checker']
        tags:
            - { name: kernel.event_listener, event: security.interactive_login, method: onSecurityInteractiveLogin }

最后是课堂上的变化PlatformAdminBundle/Listener/SecurityListener.php

namespace Clanmovil\PlatformAdminBundle\Listener;

use Symfony\Component\Finder\Exception\AccessDeniedException;
use Symfony\Component\Security\Core\Authorization\AuthorizationCheckerInterface;
use Symfony\Component\Security\Http\Event\InteractiveLoginEvent;

class SecurityListener
{

    public function __construct(AuthorizationCheckerInterface $authorizationChecker)
    {
        $this->security = $authorizationChecker;
    }

    public function onSecurityInteractiveLogin(InteractiveLoginEvent $event)
    {
        if ($this->security->isGranted('ROLE_ADMIN')) {
            // this is something for testing
            throw new AccessDeniedException(
                'Access Denied. You are ADMIN'
            );
        } elseif ($this->security->isGranted('ROLE_CHATTER')) {
            // this is something for testing
            throw new AccessDeniedException(
                'Access Denied. You are CHATTER'
            );
        }
    }
}

当我以用户身份登录时ROLE_CHATTER似乎一切正常,因为我得到了 AccessDenied 异常,但是当我尝试以用户身份登录时ROLE_ADMIN它停止工作,我回到最初的错误:Bad credentials,这是为什么?我快疯了!!

4

2 回答 2

1

您需要启用翻译:

# config.yml

framework:
    translator: ~
...

fos_user:
    db_driver: orm # or mongodb|couchdb|propel
    firewall_name: global
    user_class: AppBundle\Entity\User

https://symfony.com/doc/master/bundles/FOSUserBundle/index.html

#security.yml

security:
    firewalls:
        # ...
        global:
            pattern:  ^/
            anonymous: true
            provider:  fos_userbundle
            form_login:
                csrf_token_generator: security.csrf.token_manager
                remember_me: true
                default_target_path: root
            logout:
                path: fos_user_security_logout
                target: root
            remember_me:
                secret:   '%secret%'
                lifetime: 604800 # 1 week in seconds

    access_control:
        - { path: ^/admin/login$, role: IS_AUTHENTICATED_ANONYMOUSLY }
        - { path: ^/admin/register, role: IS_AUTHENTICATED_ANONYMOUSLY }
        - { path: ^/admin/resetting, role: IS_AUTHENTICATED_ANONYMOUSLY }

        - { path: ^/chat/, role: ROLE_CHATTER }
        - { path: ^/admin/, role: ROLE_ADMIN }

http://symfony.com/doc/current/components/security/authentication.html

此外,您应该使用相同的防火墙,因为它们共享相同的配置,并且您已经根据用户角色定义了访问控制。

您只需要为“/”创建一个核心控制器:

# routing.yml
root:
    path: /
    defaults: { _controller: Your\Namespace\Controller\RootController::rootAction }

namespace Your\Namespace\Controller;

use Symfony\Bundle\FrameworkBundle\Controller;

class RootControler extends Controller
{
    public function rootAction()
    {
        $security = $this->get('security.authorization_checker');

        if ($security->isGranted('ROLE_ADMIN')) {
            return $this->redirectToRoute('your_admin_root');
        }

        if ($security->isGranted('ROLE_CHATTER')) {
            return $this->redirectToRoute('your_chatter_route');
        }

        return $this->redirectToRoute('fos_user_security_login');
    }
}
于 2016-01-15T12:24:34.963 回答
0

问题可能出在路由上。由于在这两种情况下您只使用 FOSUserBundle 中的一个来进行身份验证,因此您应该尝试为每个防火墙创建两个不同的路由,例如:

#FOSUser
fos_user_security:
    resource: "@FOSUserBundle/Resources/config/routing/security.xml"
    prefix: /admin

#FOSUser
fos_user_security:
    resource: "@FOSUserBundle/Resources/config/routing/security.xml"
    prefix: /chat
于 2016-01-15T13:40:36.917 回答