是否可以为特定路由/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 }
当您使用FOSUserBundle时,登录表单的呈现将在SecurityController::renderLogin()
中进行。
解决方案基本上是:
- 重写SecurityController
- 添加角色
IS_AUTHENTICATD_ANONYMOUSLY
的检查 - 如果找不到角色,则将用户重定向到另一个页面
我假设您已经创建了一个扩展FOSUserBundle的捆绑包,其中包含您的User
实体。
我假设这个束被称为YourUserBundle
,并且位于src/Your/Bundle/UserBundle
。
现在复制(不剪切)SecurityController
vendor/friendsofsymfony/user-bundle/src/FOS/UserBundle/Controller/SecurityController.php
到(以便覆盖FOSUserBundle提供的)
src/Your/Bundle/UserBundle/Controller/SecurityController.php
添加RedirectResponse
的use语句并编辑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.authorization_checker
代替security.context
。
http://symfony.com/blog/new-in-symfony-2-6-security-component-improvements
在我看来,覆盖登录表单的呈现是在错误的地方提供答案。登录表单的呈现不负责登录。这是登录请求的结果。它在未来的其他地方可能会有其他用途,在这些情况下,你会破坏功能。
对我来说,覆盖登录操作似乎更好。这是负责处理登录请求的实际组件。
要执行此操作,请覆盖Security Controller中的登录操作。假设您的MyProject项目中有一个MyUserBundle,它扩展了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);
}
}
注意:我正在使用Symfony3.0.4@dev
这个答案是基于@nifr@mirk提供的答案和@Ronan的评论。
为了防止用户访问登录页面,我覆盖SecurityController,如下所示:
<?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);
}
}
我还将其添加到RegistrationController中以执行完全相同的操作。
希望它能帮助到你们中的一些人。
另一个基于@nifr答案的解决方案。仅覆盖捆绑包控制器中的renderLogin
函数。另请参阅。如何使用Bundle继承来覆盖Bundle 的部分
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 }
希望这对你有所帮助。:)