如何在Symfony2的控制器中检查用户是否已登录?

79

我在这里阅读了如何在Symfony2网站的twig模板中通过内部检查用户登录状态。 这里 然而,我需要知道如何从控制器中检查用户是否已登录。我非常确定以下代码是正确的:

$user = $this->get('security.context')->getToken()->getUser();

但它总是返回一些东西,例如已登录的用户或匿名用户。

有什么想法吗?


你能不能检查一下 $user 是否不等于 "anon."? - Lorenzo Marcon
嗯,我在寻找更加“安全”的方式。难道没有其他方法吗?比如说调用某个函数? - JeanValjean
7个回答

153

警告:仅检查 'IS_AUTHENTICATED_FULLY' 将返回 false,如果用户已经使用“记住我”功能登录。

根据Symfony 2文档,有三种可能性:

IS_AUTHENTICATED_ANONYMOUSLY - 自动分配给在防火墙保护的站点部分中的用户, 但实际上没有登录。只有允许匿名访问才可能发生。

IS_AUTHENTICATED_REMEMBERED - 自动为通过记住我的Cookie验证的用户分配。

IS_AUTHENTICATED_FULLY - 自动分配给在当前会话期间提供了其登录详细信息 的用户。

这些角色代表三个认证级别:

如果您拥有 IS_AUTHENTICATED_REMEMBERED 角色,则还具有 IS_AUTHENTICATED_ANONYMOUSLY 角色。如果您拥有 IS_AUTHENTICATED_FULLY 角色,则也具有另外两个角色。 换句话说,这些角色代表三个逐渐增强的认证“强度”级别。

我遇到一个问题,在只检查 'IS_AUTHENTICATED_FULLY' 的页面上,我们系统的使用了“记住我”功能的用户被视为根本没有登录。

因此,解决方案是如果用户不完全验证,则要求他们重新登录或检查已记住的角色:

$securityContext = $this->container->get('security.authorization_checker');
if ($securityContext->isGranted('IS_AUTHENTICATED_REMEMBERED')) {
    // authenticated REMEMBERED, FULLY will imply REMEMBERED (NON anonymous)
}

希望这能帮助到有需要的人,不再犯和我一样的错误。在查找如何检查Symfony 2上某个用户是否已登录时,我用了这篇文章作为参考。

来源:http://symfony.com/doc/2.3/cookbook/security/remember_me.html#forcing-the-user-to-re-authenticate-before-accessing-certain-resources


4
实际上,你可以只使用 $securityContext->isGranted('IS_AUTHENTICATED_REMEMBERED'),因为角色是有等级的。所以拥有 IS_AUTHENTICATED_FULLY 也意味着用户同时拥有 IS_AUTHENTICATED_REMEMBERED - theunraveler
3
不正确。IS_AUTHENTICATED_REMEMBERED只有在用户使用“记住我”功能时返回true。拥有IS_AUTHENTICATED_FULLY确实意味着有IS_AUTHENTICATED_REMEMBERED,但反之则不成立。 - Bryson
4
好的。如果 IS_AUTHENTICATED_FULLY 也保证用户已经 IS_AUTHENTICATED_REMEMBERED,那么你只需要检查 IS_AUTHENTICATED_REMEMBERED 就可以了。 - theunraveler
1
当你有不同的角色时,该如何处理呢?例如,我有一个ROLE_USER和一个ROLE_ADMIN,这对于网站的某些区域是必需的,我想允许这两种类型的用户使用IS_AUTHENTICATED_REMEMBERED级别访问它们各自的区域。我该如何实现这一点呢? - Nick
2
顺便提一下,在2.6中可以使用$this->container->get('security.authorization_checker')代替。 - Ronan
显示剩余4条评论

56

SecurityContext将在Symfony 3.0中停用

Symfony 2.6之前,您将使用SecurityContext
为了取代SecurityContextSymfony 3.0将其停用,并采用AuthorizationChecker

对于Symfony 2.6+Symfony 3.0,请使用AuthorizationChecker


Symfony 2.6(及以下版本)

// Get our Security Context Object - [deprecated in 3.0]
$security_context = $this->get('security.context');
# e.g: $security_context->isGranted('ROLE_ADMIN');

// Get our Token (representing the currently logged in user)
$security_token = $security_context->getToken();
# e.g: $security_token->getUser();
# e.g: $security_token->isAuthenticated();
# [Careful]             ^ "Anonymous users are technically authenticated"

// Get our user from that security_token
$user = $security_token->getUser();
# e.g: $user->getEmail(); $user->isSuperAdmin(); $user->hasRole();

// Check for Roles on the $security_context
$isRoleAdmin = $security_context->isGranted('ROLE_ADMIN');
# e.g: (bool) true/false

Symfony 3.0+ (自 Symfony 2.6+ 起)

security.context 变为 security.authorization_checker
现在我们从 security.token_storage 获取我们的 token,而不是从 security.context 中获取。

// [New 3.0] Get our "authorization_checker" Object
$auth_checker = $this->get('security.authorization_checker');
# e.g: $auth_checker->isGranted('ROLE_ADMIN');

// Get our Token (representing the currently logged in user)
// [New 3.0] Get the `token_storage` object (instead of calling upon `security.context`)
$token = $this->get('security.token_storage')->getToken();
# e.g: $token->getUser();
# e.g: $token->isAuthenticated();
# [Careful]            ^ "Anonymous users are technically authenticated"

// Get our user from that token
$user = $token->getUser();
# e.g (w/ FOSUserBundle): $user->getEmail(); $user->isSuperAdmin(); $user->hasRole();

// [New 3.0] Check for Roles on the $auth_checker
$isRoleAdmin = $auth_checker->isGranted('ROLE_ADMIN');
// e.g: (bool) true/false
在文档中阅读更多内容:AuthorizationChecker
如何在Twig中实现此操作?:Symfony 2:如何在模板内检查用户是否未登录?

2
在Symfony的Controller中,您只需编写$this->isGranted($role, $obj, $errMsg)即可。denyAccessUnlessGranted()函数和isGranted()函数都是调用security.authorization_checker服务上的isGranted()的快捷方式。 - Mehulkumar

46

试试这个:

if( $this->container->get('security.context')->isGranted('IS_AUTHENTICATED_FULLY') ){
    // authenticated (NON anonymous)
}

更多信息:

"匿名用户在技术上是已认证的,也就是说一个匿名用户对象的isAuthenticated()方法会返回true。 要检查你的用户是否真正已认证,请检查IS_AUTHENTICATED_FULLY角色。"

来源:http://symfony.com/doc/current/book/security.html


是的!它可以运行...非常感谢!不过,您认为 $user != "anon." 足够安全吗?我的担忧是新版本可能会更改匿名用户返回的值!这是可能的吗? - JeanValjean
2
嗯...既然Symfony提供了这个解决方案,我建议你使用它(isGranted)。我不认为他们会改变安全组件这样基本的功能的行为。顺便说一句,使用isGranted比简单的字符串比较更专业和干净。 - Lorenzo Marcon
再次感谢您提供完整的答案! - JeanValjean
3
顺便说一句,在2.6版本中新引入了$this->container->get('security.authorization_checker'),请使用它代替原来的方法。 - Ronan
您请求了一个不存在的服务“security.context”。 - fdrv
security.context已被弃用。 - Rodrigo Lopez Guerra

9

补充Anil所说的,symfony3中,您可以使用$this->getUser()来判断用户是否已登录,像if(!$this->getUser()) {}这样的简单条件就可以做到。

如果您查看基本控制器中可用的源代码,它也会执行Anil定义的确切操作。


$this->getUser()方法非常有效,我在Symfony 5中进行了测试。另外,在控制器中,假设你有$someVar = $this->getUser();并将其传递给twig。然后你可以在body标签的某个地方做{{dump(someVar)}}或{% dump(someVar) %},你将得到null或用户对象的内容。 - Ali

8

如果您使用SensioFrameworkExtraBundle中的安全注释,则可以使用一些表达式(这些表达式在\Symfony\Component\Security\Core\Authorization\ExpressionLanguageProvider中定义):

  • @Security("is_authenticated()"):检查用户是否已经通过身份验证且不是匿名用户
  • @Security("is_anonymous()"):检查当前用户是否为匿名用户
  • @Security("is_fully_authenticated()"):相当于is_granted('IS_AUTHENTICATED_FULLY')
  • @Security("is_remember_me()"):相当于is_granted('IS_AUTHENTICATED_REMEMBERED')

6
如果您使用角色,可以检查ROLE_USER,这是我使用的解决方案:
if (TRUE === $this->get('security.authorization_checker')->isGranted('ROLE_USER')) {
    // user is logged in
} 

假设您的应用程序将“ROLE_USER”分配给所有人。并非所有应用程序都会这样做。 - Brian

1

最好的做法是从一个baseController继承并实现一些基本函数。实现一个检查用户实例是否为null的函数,例如:如果用户来自Userinterface,则没有用户登录。

/**

*/
class BaseController extends AbstractController
{

    /**
     * @return User

     */
    protected function getUser(): ?User
    {
        return parent::getUser();
    }

    /**
     * @return bool
     */
    protected function isUserLoggedIn(): bool
    {
        return $this->getUser() instanceof User;
    }
}

我不确定为什么会被踩。我是Symfony的初学者,但从控制器访问 $this->user() 是完全可行的。 - Max
因为我认为这样做实际上不是一个好的做法。我更喜欢组合的方式。如果另一个服务想知道用户是否已登录,怎么办?而且我不明白为什么要重写getUser()方法。顶部的注释是错误和无用的。 - Tomsgu

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接