Связка пользователей - Как перенаправить уже вошедших в систему пользователей при попытке доступа к пути входа
Возможно ли выполнить автоматическое перенаправление на некоторый маршрут (т.Е./) для определенного маршрута /login
только для пользователей, которые являются AUTHENTICATED
? и как?
Я использую FOSUserBundle.
Это моя конфигурация безопасности:
security:
encoders:
FOS\UserBundle\Model\UserInterface: sha512
role_hierarchy:
ROLE_ADMIN: ROLE_USER
ROLE_SUPER_ADMIN: ROLE_ADMIN
providers:
fos_userbundle:
id: fos_user.user_provider.username_email
firewalls:
main:
pattern: ^/
form_login:
provider: fos_userbundle
csrf_provider: form.csrf_provider
login_path: /accedi
check_path: /login_check
default_target_path: /
oauth:
resource_owners:
facebook: "/login/check-facebook"
google: "/login/check-google"
login_path: /accedi
failure_path: /accedi
default_target_path: /
oauth_user_provider:
service: my_user_provider
logout:
path: /logout
target: /
invalidate_session: false
anonymous: ~
login:
pattern: ^/login$
security: false
remember_me:
key: "%secret%"
lifetime: 31536000 # 365 days in seconds
path: /
domain: ~
oauth_authorize:
pattern: ^/oauth/v2/auth
form_login:
provider: fos_userbundle
check_path: _security_check
login_path: _demo_login
anonymous: true
oauth_token:
pattern: ^/oauth/v2/token
security: false
access_control:
- { path: ^/login$, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/register, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/resetting, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/accedi$, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/registrati, role: IS_AUTHENTICATED_ANONYMOUSLY }
5 answers
При использовании FOSUserBundle отображение формы входа происходит в SecurityController::renderLogin()
.
Решение в основном таково:
- переопределение контроллера безопасности
- добавление проверки для роли
IS_AUTHENTICATD_ANONYMOUSLY
- перенаправление пользователя на другую страницу, если роль не была найдена
Я предполагаю, что вы уже создали пакет, расширяющий FOSUserBundle, который содержит вашу сущность User
.
Я предполагаю, что этот пакет называется YourUserBundle
и находится по адресу src/Your/Bundle/UserBundle
.
Теперь скопируйте ( не вырезайте ) Контроллер безопасности
vendor/friendsofsymfony/user-bundle/src/FOS/UserBundle/Controller/SecurityController.php
Для (чтобы переопределить тот, который предоставлен FOSUserBundle)
src/Your/Bundle/UserBundle/Controller/SecurityController.php
Добавьте инструкцию use-для RedirectResponse
и отредактируйте метод renderLogin()
следующим образом:
use Symfony\Component\HttpFoundation\RedirectResponse;
// ...
protected function renderLogin(array $data)
{
if (false === $this->container->get('security.context')->isGranted('IS_AUTHENTICATED_ANONYMOUSLY')) {
return new RedirectResponse('/', 403);
}
$template = sprintf('FOSUserBundle:Security:login.html.%s', $this->container->getParameter('fos_user.template.engine'));
return $this->container->get('templating')->renderResponse($template, $data);
}
Обновление
Теперь вместо security.context
используйте security.authorization_checker
.
Http://symfony.com/blog/new-in-symfony-2-6-security-component-improvements
Мне кажется, что переопределение отображения формы входа в систему дает ответ в неправильном месте. Отображение формы входа в систему не является ответственным за вход в систему. Это результат запроса на вход в систему. В будущем у него могут быть другие способы использования в других местах, и вы нарушите функциональность в этих ситуациях.
Переопределение действия входа в систему кажется мне лучше. Это фактический компонент, отвечающий за обработку запроса на вход.
Для этого переопределите действие входа в систему в контроллере безопасности. Допустим, у вас есть myuserbundle в вашем проекте MyProject, который расширяет FOSUserBundle.
<?php
namespace MyProject\MyUserBundle\Controller;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RedirectResponse;
use FOS\UserBundle\Controller\SecurityController as BaseSecurityController;
class SecurityController extends BaseSecurityController
{
/**
* Overriding login to add custom logic.
*/
public function loginAction(Request $request)
{
if( $this->container->get('security.context')->isGranted('IS_AUTHENTICATED_REMEMBERED') ){
// IS_AUTHENTICATED_FULLY also implies IS_AUTHENTICATED_REMEMBERED, but IS_AUTHENTICATED_ANONYMOUSLY doesn't
return new RedirectResponse($this->container->get('router')->generate('some_route_name_in_my_project', array()));
// of course you don't have to use the router to generate a route if you want to hard code a route
}
return parent::loginAction($request);
}
}
ПРИМЕЧАНИЕ: Я использую Symfony 3.0.4@dev
Этот ответ основан и на том, который предоставил @nifr @mirk, и на комментарии @Ronan.
Чтобы запретить пользователю доступ к странице входа в систему, я переопределяю контроллер безопасности следующим образом:
<?php
namespace AppBundle\Controller;
use Symfony\Component\HttpFoundation\RedirectResponse;
use FOS\UserBundle\Controller\SecurityController as BaseController;
class SecurityController extends BaseController
{
/**
* Renders the login template with the given parameters. Overwrite this function in
* an extended controller to provide additional data for the login template.
*
* @param array $data
*
* @return \Symfony\Component\HttpFoundation\Response
*/
protected function renderLogin (array $data)
{
// This little if do the trick
if ($this->container->get('security.authorization_checker')->isGranted('ROLE_USER')) {
return new RedirectResponse($this->container->get ('router')->generate ('app_generation_page'));
}
$template = sprintf ('FOSUserBundle:Security:login.html.twig');
return $this->container->get ('templating')->renderResponse ($template, $data);
}
}
Я также добавил его в контроллер регистрации, чтобы сделать то же самое.
Надеюсь, это поможет некоторым из вас.
Другое решение, основанное на ответе @nifr. Перезапись только функции renderLogin
в вашем контроллере пакетов. Смотрите также.
Как использовать наследование пакета для переопределения частей пакета
namespace MyProject\UserBundle\Controller;
//namespace FOS\UserBundle\Controller;
use Symfony\Component\HttpFoundation\RedirectResponse;
use \FOS\UserBundle\Controller\SecurityController as BaseController;
class SecurityController extends BaseController {
/**
* Renders the login template with the given parameters. Overwrite this function in
* an extended controller to provide additional data for the login template.
*
* @param array $data
*
* @return \Symfony\Component\HttpFoundation\Response
*/
protected function renderLogin(array $data) {
if (true === $this->container->get('security.context')->isGranted('ROLE_USER')) {
return new RedirectResponse($this->container->get('router')- >generate('homeroute'));
}
$template = sprintf('FOSUserBundle:Security:login.html.%s', $this->container->getParameter('fos_user.template.engine'));
return $this->container->get('templating')->renderResponse($template, $data);
}
}
Я использую маршрутизацию и безопасность, чтобы включить это.
#routing.yml
index:
path: /
defaults: { _controller: AppBundle:Base:index }
methods: [GET]
login:
path: /login
defaults: { _controller: AppBundle:Security:login }
methods: [GET]
Если пользователь вошел в систему, он перенаправляется на панель мониторинга. Если нет, он увидит маршрут входа в систему.
#security.yml
access_control:
- { path: ^/login$, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/dashboard, role: ROLE_USER }
Надеюсь, это поможет вам. :)