Symfony2拒绝基于自定义状态的用户登录

时间:2014-04-25 00:26:14

标签: php symfony authentication

我已经跟随guide实施身份验证/授权,我可以登录。 我从指南中的内容中得到了一个主要区别。我没有isActive属性,而是在我的数据库中有一个状态表。

我不知道如何根据状态表中的值而不是指南中引用的isActive属性来拒绝/接受登录。

我不确定要发布什么代码,因为它的工作原理与指南相同,我非常确定Symfony安全系统会处理我无法看到的所有身份验证内容。

即使你只是指出我正确的方向,我将不胜感激。

修改

使用ChadSikorra的建议我想出了这段代码来实现AdvancedUserInterface函数:

public function isAccountNonExpired()
    {
        $status = $this->getTblStatus()->getStatustext();

        switch ($status){
            case "expired":
                return false;
            default:
                return true;
        }
    }

    public function isAccountNonLocked()
    {
        $status = $this->getTblStatus()->getStatustext();

        switch ($status){
            case "locked":
                return false;
            case "suspended":
                return false;
            case "registered":
                return false;
            default:
                return true;
        }
    }

    public function isCredentialsNonExpired()
    {
        return $this->pwdexpired;
    }

    public function isEnabled()
    {
        $status = $this->getTblStatus()->getStatustext();

        if($status != 'active')
            return false
        else
            return true;
    }

我接下来的问题是如何处理用户具有其中一种状态时引发的异常?

根据我到目前为止的情况,我认为通过捕获loginAction中的错误是可行的。我不知道该怎么做就是找出错误,但我会继续挖掘。

/**
     * @Route("/Login", name="wx_exchange_login")
     * @Template("WXExchangeBundle:User:login.html.twig")
     * User login - Open to public
     * Authenticates users to the system
     */
    public function loginAction(Request $request)
    {
        $session = $request->getSession();

        if ($this->get('security.context')->isGranted('IS_AUTHENTICATED_REMEMBERED'))
        {
            // redirect authenticated users to homepage 
            return $this->redirect($this->generateUrl('wx_exchange_default_index')); 
        }

        // get the login error if there is one
        if ($request->attributes->has(SecurityContext::AUTHENTICATION_ERROR)) {
            $error = $request->attributes->get(
                SecurityContext::AUTHENTICATION_ERROR
            );
        } else {
            $error = $session->get(SecurityContext::AUTHENTICATION_ERROR);
            $session->remove(SecurityContext::AUTHENTICATION_ERROR);
        }

        if($error instanceof LockedException)
    {
    }

        return $this->render(
            'WXExchangeBundle:User:login.html.twig',
            array(
                // last username entered by the user
                'last_username' => $session->get(SecurityContext::LAST_USERNAME),
                'error'         => $error,
            )
        );
    }

我现在能够检查Exception的类型,但我不知道如何获取特定状态,以便我可以重定向到正确的位置。这是这个难题的最后一部分。

1 个答案:

答案 0 :(得分:3)

您可以在用户实体上添加映射到自定义状态表,如下所示:

  /**
   * @ORM\OneToOne(targetEntity="AccountStatus")
   * @ORM\JoinColumn(name="status_id", referencedColumnName="id", nullable=true)
   */
  private $accountStatus;

这还需要创建一个描述自定义状态表的实体。然后,您可以通过实现您链接的指南中引用的Symfony\Component\Security\Core\User\AdvancedUserInterface在您的用户实体中使用此映射。然后实现类似这样的isEnabled函数......

public function isEnabled()
{
    return $this->getAccountStatus()->getIsActive(); /* Or whatever you named it */
}

修改

基于AdvancedUserInterface的{​​{3}},如果您想要使用自定义逻辑来处理不同的状态,则需要注册异常监听器......

  

如果您需要为任何这些情况执行自定义逻辑,那么   你需要注册一个异常监听器并注意   每种情况下抛出的特定异常实例。所有例外都是   AccountStatusException的子类

有一篇非常好的Cookbook文章用于创建类似API Doc的内容。此实例中的基本过程是为侦听器创建类...

的src / Acme公司/ DemoBundle /事件监听/ AcmeExceptionListener.php

namespace Acme\DemoBundle\EventListener;

use Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Security\Core\Exception\DisabledException;
use Symfony\Component\Security\Core\Exception\LockedException;

class AcmeExceptionListener
{
    public function onKernelException(GetResponseForExceptionEvent $event)
    {
        $exception = $event->getException();

        if ($exception instanceof DisabledException) {
            // Customize your response object to display the exception details
            $response = new Response();
            $response->setContent('<html><body><h1>Custom disabled page!</h1></body></html>');

            // Send the modified response object to the event
            $event->setResponse($response);
        }
        elseif ($exception instanceof LockedException) {
            // Or render a custom template as a subrequest instead...
            $kernel = $event->getKernel();
            $response  = $kernel->forward('AcmeDemoBundle:AccountStatus:locked', array(
                'exception' => $exception,
            ));

            $event->setResponse($response);
        }
        // ... and so on
    }
}

以上只是基本的例子,但它无论如何都会给你一个要点。从技术上讲,我猜你也可以通过扩展AccountStatusException来制作自定义异常,然后将它们放入你的AdvancedUserInterface实现的逻辑中。然后你会确切地知道你正在捕捉的状态。无论如何,请确保将监听器注册为服务。

应用程序/配置/ config.yml

services:
    kernel.listener.your_listener_name:
        class: Acme\DemoBundle\EventListener\AcmeExceptionListener
        tags:
            - { name: kernel.event_listener, event: kernel.exception, method: onKernelException }

另一种方法是实现某种自定义用户检查器。请参阅此问题:here