问题描述
我正在Symfony 2.8.x应用程序中工作,我需要设置两个有担保区域:chat和admin.这意味着chat和admin将使用相同的登录模板(如果可能的话,我不需要为此目的设置不同的登录模板).在此处询问之前,我已经搜索过 google ,有一些相关的内容,我读了很多有关此主题的文章: 1 , 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上覆盖了登录模板. (如果需要来源,我只能提供不超过帖子比已经更长的帖子).
当我调用URL:http://domain.tld/app_dev.php/admin并尝试登录时,我会收到此错误:
找不到翻译. 上下文:{" ID": " Symfony \ Component \ Security \ Security \ Core \异常\ BadCredentialSexception: 不好的信用史.在 /var/www/html/platform-cm/vendor/symfony/symfony/symfony/symfony/symfony/component/security/core/core/authentication/authentication/provider/userauthicationalicationprovider.php:90 \ nstack 跟踪:\ 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 }
然后,我为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); } }
我遇到了同样的问题,也许我做错了什么,我没有看到,但我接受了任何想法.这里有什么问题?
3rd方法
我对我的代码进行了审查,并在@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 }
services.yml上的更改基本上是修复参数,因为security.context已在Symfony 2.6+中分开,尽管我根本不使用它:
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的用户登录时,由于我得到了访问的例外,一切似乎都可以正常工作,但是当我尝试以ROLE_ADMIN的用户登录时,它会停止工作,然后回到初始错误:Bad credentials , 为什么是这样?我发疯了!
推荐答案
您需要启用翻译:
# config.yml framework: translator: ~ ... fos_user: db_driver: orm # or mongodb|couchdb|propel firewall_name: global user_class: AppBundle\Entity\User
#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 }
您也应该使用相同的防火墙,因为它们共享相同的配置,并且已经根据用户角色定义了访问控件.
您只需要为'/'as创建一个核心控制器:
# 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'); } }
其他推荐答案
问题可能在路由中.由于在这两种情况下,您仅使用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
问题描述
I'm working in a Symfony 2.8.x app and I need to setup two secured areas: chat and admin. This means that chat and admin will use the same login template (if this is possible and I don't need to setup different one for this purpose). I have googled before ask here and there is a few things related showing up and I read a lot of post about this topic: 1, 2, 3, 4 just as an example of them but I am doing something wrong since I can't get this working properly. This is how /app/config/security.yml looks like (just the firewalls and access_control piece of code):
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 }
Now this is the config for my bundles at 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
And for FOSUserBundle I have tried this two (both without success and each at a time):
#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
I have overwrite the login template at app/Resources/FOSUserBundle/views/Security/login.html.twig. (if source is needed I can provide just ommit for not make the post longer than it's already).
When I call the URL: http://domain.tld/app_dev.php/admin and try to login I got this error:
Translation not found. Context: { "id": "Symfony\Component\Security\Core\Exception\BadCredentialsException: Bad credentials. in /var/www/html/platform-cm/vendor/symfony/symfony/src/Symfony/Component/Security/Core/Authentication/Provider/UserAuthenticationProvider.php:90\nStack trace:\n#0
(I can provide the full stacktrace if needed)
this is weird to me but perhaps it's caused for a bad configuration since I have double checked credentials.
When I call the URL: http://domain.tld/app_dev.php/chat and try to login I got Access Denied but it's right because I am redirected to http://domain.tld/app_dev.php/admin/. Can any give me some help on this configuration? I am stuck and can't move forward because of this
2nd approach
This is a second approach bassed on @heah suggestion using a listener but is not working too I am still getting the same "Bad credentials" message and can't login at all. I have changed back the routing.yml to this:
#FOSUser fos_user: resource: "@FOSUserBundle/Resources/config/routing/all.xml"
I have changed back the security.yml to this:
security: ... firewalls: admin: pattern: ^/ anonymous: ~ form_login: provider: 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 }
Then I have defined a listener for the event security.interactive_login as suggested in app/config/config.yml:
parameters: account.security_listener.class: PlatformAdminBundle\Listener\SecurityListener
Then at 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 }
And finally here is the class definition at 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); } }
I am running the same issue, again, perhaps I am doing something wrong and I am not seeing but I accept any ideas. What could be wrong here?
3rd approach
I have take a review to my code and change it slighty mostly following @heah suggestions. So, now security.yml is as follow:
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 }
the changes at services.yml are basically fix the arguments since security.context has been split in Symfony 2.6+ although I am not using it at all:
services: ... account.security_listener: class: %account.security_listener.class% arguments: ['@security.authorization_checker'] tags: - { name: kernel.event_listener, event: security.interactive_login, method: onSecurityInteractiveLogin }
And lastly the changes at the class 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' ); } } }
When I login as user with ROLE_CHATTER everything seems to work since I got the AccessDenied exception but when I try to login as a user with ROLE_ADMIN it stop working and I come back to the initial error: Bad credentials, why is this? I am getting crazy!!
推荐答案
You need to enable translation :
# config.yml framework: translator: ~ ... fos_user: db_driver: orm # or mongodb|couchdb|propel firewall_name: global user_class: AppBundle\Entity\User
see 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 }
see http://symfony.com/doc/current/components/security/authentication.html
Also you should use the same firewall since they share the same configuration and you already define access controls based on user role.
You would only need to create a core controller for '/' as :
# routing.yml root: path: / defaults: { _controller: Your\Namespace\Controller\RootController::rootAction }
and
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'); } }
其他推荐答案
The issue may be in the routing. Since in both cases your are using only one from FOSUserBundle to authenticate, you should try to create two different routes one for each firewall, example:
#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