FOSUserBundle - 更改默认配置,覆盖一些默认设置

FOSUserBundle - changes in default configuration, overriding some default settings

我是 Symfony 2 的新手。我必须在 Symfony 2 中构建一个应用程序(我使用的是 2.8 和最新版本的 FOSUser Bundle)。大部分工作已完成,但我必须对默认安全设置进行一些更改。我找了他们两天,但我对如何解决这个问题一无所知。假定的更改如下:

我知道如何覆盖 FOSUser 的某些模板,但我不清楚应该覆盖哪些文件来更改这些内容。

我注意到我的 FOSUser 使用 Symfony 2 Exceptions 文件,如果我更改了我的 Exception 文件中的消息内容,它也会在我的页面上更改,但我不知道如何让它变得更好并覆盖它,添加所有必要的功能。

我试图使用 Compiler Pass (http://symfony.com/doc/current/cookbook/service_container/compiler_passes.html) 覆盖 AuthenticationListener(来自 FOSUser),但我不知道它是否有效,因为覆盖的 Listener 中的任何更改都不可见。其实我不知道这是否是我应该覆盖的文件。

我已经检查了一些 Whosebug 问题,但我还没有找到答案。

FOSUser Bundle - Prevent Disabled users from logging in 这对我不起作用,因为用户被阻止了,我只需要覆盖异常消息并使用另一个 link 发送确认消息创建重定向。

FOS user bundle authentication 我已经尝试实施此处指出的解决方案,但它没有用,我不确定我是否真的需要这么复杂的解决方案。

提前感谢您的帮助,我有人需要看我的文件,只需编写配置,我会 post 这里有必要的。

我终于想通了所有这些事情。如果有人有类似的问题,我建议阅读 Symfony 文档中的这些主题: Overriding FOSUser B controllers Hooking into a controller

事实证明,对于所描述的功能,我需要覆盖 FOSUser Bundle 中的一些文件,有时 Controller 就足够了,有时我需要修改 EventListener(实际上我什至创建了自己的事件)。有不止一种方法。

最难的部分是一键 link 重置密码。我使用了一个标志,在发送电子邮件时设置为 false,在单击 link 时设置为 true 以防止再次使用 link。问题是,Resetting Controller 是 'executed' 两次,因此在单击提交时出现重定向,因为标志为 true。我在会话中添加了一些计数,以便在您点击提交按钮时省略检查标志的代码部分(重置控制器中重置方法的第二次使用),但它只阻止了第二次点击提交,所以实际上link不能用两次,但是可以看到两次form,这不是我想要达到的效果,但总比没有好。如果有人知道如何升级它,我将不胜感激

<?php



namespace My\UserBundle\Controller;

use FOS\UserBundle\Controller\ResettingController as FOSResettingController;
use FOS\UserBundle\FOSUserEvents;
use FOS\UserBundle\Event\FormEvent;
use FOS\UserBundle\Event\GetResponseUserEvent;
use FOS\UserBundle\Event\FilterUserResponseEvent;
use FOS\UserBundle\Model\UserInterface;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use My\UserBundle\Entity\User;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use My\UserBundle\UserEvents;

/**
 * Controller managing the resetting of the password
 *
 * @author Thibault Duplessis <thibault.duplessis@gmail.com>
 * @author Christophe Coevoet <stof@notk.org>
 */
class ResettingController extends FOSResettingController
{


    /**
     * Request reset user password: submit form and send email
     */
    public function sendEmailAction(Request $request)
    {
        $username = $request->request->get('username');

        /** @var $user UserInterface */
        $user = $this->get('fos_user.user_manager')->findUserByUsernameOrEmail($username);

        if (null === $user) {
            return $this->render('FOSUserBundle:Resetting:request.html.twig', array(
                'invalid_username' => $username
            ));
        }

        if ($user->isPasswordRequestNonExpired($this->container->getParameter('fos_user.resetting.token_ttl'))) {
            return $this->render('FOSUserBundle:Resetting:passwordAlreadyRequested.html.twig');
        }

        if (null === $user->getConfirmationToken()) {
            /** @var $tokenGenerator \FOS\UserBundle\Util\TokenGeneratorInterface */
            $tokenGenerator = $this->get('fos_user.util.token_generator');
            $user->setConfirmationToken($tokenGenerator->generateToken());
        }

        $this->get('fos_user.mailer')->sendResettingEmailMessage($user);
        $user->setPasswordRequestedAt(new \DateTime());
        $user->setPasswordRequestedClicked(false);
        $this->get('fos_user.user_manager')->updateUser($user);

        $_SESSION['views'] = 1;

        return new RedirectResponse($this->generateUrl('fos_user_resetting_check_email',
            array('email' => $this->getObfuscatedEmail($user))
        ));
    }


    /**
     * Reset user password
     */
    public function resetAction(Request $request, $token)
    {
        /** @var $formFactory \FOS\UserBundle\Form\Factory\FactoryInterface */
        $formFactory = $this->get('fos_user.resetting.form.factory');
        /** @var $userManager \FOS\UserBundle\Model\UserManagerInterface */
        $userManager = $this->get('fos_user.user_manager');
        /** @var $dispatcher \Symfony\Component\EventDispatcher\EventDispatcherInterface */
        $dispatcher = $this->get('event_dispatcher');

        $user = $userManager->findUserByConfirmationToken($token);


        //Here there is a reaction for using expired token (column confirmation token === null) - redirection to page with possibility of sending another one.
        if (null === $user) {
               return $this->redirectToRoute('fos_user_invalid_token_click');

        }



        if ($_SESSION['views'] == 1){
            $event = new GetResponseUserEvent($user, $request);
            $dispatcher->dispatch(UserEvents::RESETTING_RESET_CLICK_CHECK, $event);

            if (null !== $event->getResponse()) {
                return $event->getResponse();
            } else {
                $user->setPasswordRequestedClicked(true);
                $userManager->updateUser($user);
                $_SESSION['views']++;
                $_SESSION['views']++;
            }
        } else {
            $_SESSION['views']++;
        }

        if ($_SESSION['views'] == 5){
            $event = new GetResponseUserEvent($user, $request);
            $dispatcher->dispatch(UserEvents::RESETTING_RESET_CLICK_CHECK, $event);

            if (null !== $event->getResponse()) {
                return $event->getResponse();
            }
        }



        $event = new GetResponseUserEvent($user, $request);
        $dispatcher->dispatch(FOSUserEvents::RESETTING_RESET_INITIALIZE, $event);

        if (null !== $event->getResponse()) {
            return $event->getResponse();
        }



        $form = $formFactory->createForm();
        $form->setData($user);




        $form->handleRequest($request);


        if ($form->isValid()) {
            $event = new FormEvent($form, $request);
            $dispatcher->dispatch(FOSUserEvents::RESETTING_RESET_SUCCESS, $event);


            $userManager->updateUser($user);

            if (null === $response = $event->getResponse()) {
                $url = $this->generateUrl('fos_user_profile_show');
                $response = new RedirectResponse($url);
            }

            $dispatcher->dispatch(FOSUserEvents::RESETTING_RESET_COMPLETED, new FilterUserResponseEvent($user, $request, $response));

            return $response;
        }

        $userManager->updateUser($user);
        return $this->render('FOSUserBundle:Resetting:reset.html.twig', array(
            'token' => $token,
            'form' => $form->createView(),
        ));
    }



    public function InvalidTokenTtlMessageAction() {
        return $this->render('UserBundle:Resetting:invalidTokenTtlRes.html.twig');
    }

    public function InvalidTokenClickMessageAction() {
        return $this->render('UserBundle:Resetting:invalidTokenClickRes.html.twig');
    }


}

我的听众:

  <?php



namespace My\UserBundle\EventListener;

use FOS\UserBundle\EventListener\ResettingListener as FOSResettingListener;
use FOS\UserBundle\FOSUserEvents;
use My\UserBundle\UserEvents;
use FOS\UserBundle\Event\FormEvent;
use FOS\UserBundle\Event\GetResponseUserEvent;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\Routing\Generator\UrlGeneratorInterface;
use My\UserBundle\Entity\User;

class ResettingListener extends FOSResettingListener
{
    private $router;
    private $tokenTtl;

    public function __construct(UrlGeneratorInterface $router, $tokenTtl)
    {
        $this->router = $router;
        $this->tokenTtl = $tokenTtl;
    }

    public static function getSubscribedEvents()
    {
        return array(
            UserEvents::RESETTING_RESET_CLICK_CHECK => 'onResettingClickCheck',
            FOSUserEvents::RESETTING_RESET_INITIALIZE => 'onResettingResetInitialize',
            FOSUserEvents::RESETTING_RESET_SUCCESS => 'onResettingResetSuccess',

        );
    }

    public function onResettingClickCheck(GetResponseUserEvent $event){
        //checking if link hasn't expired due to its usage
        if ($event->getUser()->isPasswordRequestedClicked() === true){
            $event->setResponse(new RedirectResponse($this->router->generate('fos_user_invalid_token_click')));
        }
    }

    public function onResettingResetInitialize(GetResponseUserEvent $event)
    {
        //checking if link hasn't expired due to exceeding token Ttl
        if (!$event->getUser()->isPasswordRequestNonExpired($this->tokenTtl)) {
            $event->setResponse(new RedirectResponse($this->router->generate('fos_user_invalid_token_ttl')));
        }

    }

    public function onResettingResetSuccess(FormEvent $event)
    {

        /** @var $user \FOS\UserBundle\Model\UserInterface */
        $user = $event->getForm()->getData();

        $user->setConfirmationToken(null);
        $user->setPasswordRequestedAt(null);
        $user->setEnabled(true);



    }
}

和我的用户实体:

 <?php

namespace My\UserBundle\Entity;

use Doctrine\ORM\Mapping as ORM;
use FOS\UserBundle\Model\User as BaseUser;
use My\BackendBundle\Entity;
use Gedmo\Mapping\Annotation as Gedmo;
use Symfony\Component\Security\Core\User\UserInterface;
use Doctrine\Common\Collections\ArrayCollection;


/**
 * User
 *
 * @ORM\Table(name="user")
 * @ORM\Entity(repositoryClass="My\UserBundle\Repository\UserRepository")
 */
class User extends BaseUser
{
    /**
     * @var int
     *
     * @ORM\Column(name="id", type="integer", nullable = false)
     * @ORM\Id
     * @ORM\GeneratedValue(strategy="AUTO")
     */
    protected $id;


    /**
     * @Gedmo\Slug(fields={"username"})
     * @ORM\Column(length=128, unique=true)
     */
    private $slug;


    /**
     *
     * @ORM\ManyToMany(targetEntity="\My\BackendBundle\Entity\Event", mappedBy="users")
     * @ORM\JoinColumn(name="id", referencedColumnName="id", nullable=false)
     * @ORM\OrderBy({"date"="ASC"})
     *
     */
    protected $events;



    /**
     * @var \Doctrine\Common\Collections\ArrayCollection $event_org
     * @ORM\OneToMany(targetEntity="\My\BackendBundle\Entity\Event", mappedBy="user_org", cascade={"all"})
     */
    protected $event_org;



    /**
     * @var \DateTime
     * @ORM\Column(name="confirmation_token_requested_at", type="datetime")
     */
    protected $confirmationTokenRequestedAt;


    /**
     * @var boolean
     * @ORM\Column(name="password_requested_clicked", type="boolean", nullable=true)
     */
    protected $passwordRequestedClicked;





    public function __toString()
    {
        return $this->getUsername();
    }


    /**
     * Get id
     *
     * @return int
     */
    public function getId()
    {
        return $this->id;
    }

    public function __construct()
    {
        parent::__construct();
        $this->event_org = new \Doctrine\Common\Collections\ArrayCollection();


    }

    /**
     * Add event
     *
     * @param \My\BackendBundle\Entity\Event $event
     *
     * @return User
     */
    public function addEvent(\My\BackendBundle\Entity\Event $event)
    {
        $this->events[] = $event;
        $event->addUser($this);

        return $this;
    }

    /**
     * Remove event
     *
     * @param \My\BackendBundle\Entity\Event $event
     */
    public function removeEvent(\My\BackendBundle\Entity\Event $event)
    {
        $this->events->removeElement($event);
    }

    /**
     * Get events
     *
     * @return \Doctrine\Common\Collections\Collection
     */
    public function getEvents()
    {
        return $this->events;
    }






    /**
     * Set slug
     *
     * @param string $slug
     *
     * @return User
     */
    public function setSlug($slug)
    {
        $this->slug = $slug;

        return $this;
    }

    /**
     * Get slug
     *
     * @return string
     */
    public function getSlug()
    {
        return $this->slug;
    }

    /**
     * Add eventOrg
     *
     * @param \My\BackendBundle\Entity\Event $eventOrg
     *
     * @return User
     */
    public function addEventOrg(\My\BackendBundle\Entity\Event $eventOrg)
    {
        $this->event_org[] = $eventOrg;

        return $this;
    }

    /**
     * Remove eventOrg
     *
     * @param \My\BackendBundle\Entity\Event $eventOrg
     */
    public function removeEventOrg(\My\BackendBundle\Entity\Event $eventOrg)
    {
        $this->event_org->removeElement($eventOrg);
    }

    /**
     * Get eventOrg
     *
     * @return \Doctrine\Common\Collections\Collection
     */
    public function getEventOrg()
    {
        return $this->event_org;
    }

        /**
     * Set confirmationTokenRequestedAt
     *
     * @param \DateTime $confirmationTokenRequestedAt
     *
     * @return User
     */
    public function setConfirmationTokenRequestedAt(\DateTime $date = null)
    {
        $this->confirmationTokenRequestedAt = $date;

        return $this;
    }

    /**
     * Gets the timestamp that the user requested a confirmation_token.
     *
     * @return null|\DateTime
     */
    public function getConfirmationTokenRequestedAt()
    {
        return $this->confirmationTokenRequestedAt;
    }

    public function isConfirmationTokenNonExpired($ttl)
    {

        return $this->getConfirmationTokenRequestedAt() instanceof \DateTime &&
        $this->getConfirmationTokenRequestedAt()->getTimestamp() + $ttl > time();
    }

    /**
     * Set passwordRequestedClicked
     *
     * @param boolean $passwordRequestedClicked
     *
     * @return User
     */
    public function setPasswordRequestedClicked($boolean)
    {
        $this->passwordRequestedClicked = (Boolean) $boolean;

        return $this;
    }

    /**
     * Get passwordRequestedClicked
     *
     * @return boolean
     */
    public function getPasswordRequestedClicked()
    {
        return $this->passwordRequestedClicked;
    }

    /**
     * Checks whether the user has used password request.
     *
     *
     * @return Boolean true if the user is enabled, false otherwise
     */
    public function isPasswordRequestedClicked() {
        return $this->passwordRequestedClicked;
    }
}

如果有人想获取剩余问题的代码,请给我留言,我会在这里提供:)。

重置控制器:

<?php
namespace My\UserBundle\Controller;

use FOS\UserBundle\Controller\ResettingController as FOSResettingController;
use FOS\UserBundle\FOSUserEvents;
use FOS\UserBundle\Event\FormEvent;
use FOS\UserBundle\Event\GetResponseUserEvent;
use FOS\UserBundle\Event\FilterUserResponseEvent;
use FOS\UserBundle\Model\UserInterface;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use My\UserBundle\Entity\User;
use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route;
use My\UserBundle\UserEvents;

class ResettingController extends FOSResettingController

{

public function sendEmailAction(Request $request)
{
    $username = $request->request->get('username');

    $user = $this->get('fos_user.user_manager')->findUserByUsernameOrEmail($username);

    if (null === $user) {
        return $this->render('FOSUserBundle:Resetting:request.html.twig', array(
            'invalid_username' => $username
        ));
    }

    if ($user->isPasswordRequestNonExpired($this->container->getParameter('fos_user.resetting.token_ttl'))) {
        return $this->render('FOSUserBundle:Resetting:passwordAlreadyRequested.html.twig');
    }

    if (null === $user->getConfirmationToken()) {
        $tokenGenerator = $this->get('fos_user.util.token_generator');
        $user->setConfirmationToken($tokenGenerator->generateToken());
    }

    $this->get('fos_user.mailer')->sendResettingEmailMessage($user);
    $user->setPasswordRequestedAt(new \DateTime());
    $user->setPasswordRequestedClicked(false);
    $this->get('fos_user.user_manager')->updateUser($user);

    $_SESSION['views'] = 1;

    return new RedirectResponse($this->generateUrl('fos_user_resetting_check_email',
        array('email' => $this->getObfuscatedEmail($user))
    ));
}


public function resetAction(Request $request, $token)
{
    $formFactory = $this->get('fos_user.resetting.form.factory');
    $userManager = $this->get('fos_user.user_manager');
    $dispatcher = $this->get('event_dispatcher');

    $user = $userManager->findUserByConfirmationToken($token);


    //Here there is a reaction for using expired token (column confirmation token === null) - redirection to page with possibility of sending another one.
    if (null === $user) {
           return $this->redirectToRoute('fos_user_invalid_token_click');

    }

    if ($_SESSION['views'] == 1){
        $event = new GetResponseUserEvent($user, $request);
        $dispatcher->dispatch(UserEvents::RESETTING_RESET_CLICK_CHECK, $event);

        if (null !== $event->getResponse()) {
            return $event->getResponse();
        } else {
            $user->setPasswordRequestedClicked(true);
            $userManager->updateUser($user);
            $_SESSION['views']++;
            $_SESSION['views']++;
        }
    } else {
        $_SESSION['views']++;
    }

    if ($_SESSION['views'] == 5){
        $event = new GetResponseUserEvent($user, $request);
        $dispatcher->dispatch(UserEvents::RESETTING_RESET_CLICK_CHECK, $event);

        if (null !== $event->getResponse()) {
            return $event->getResponse();
        }
    }

    $event = new GetResponseUserEvent($user, $request);
    $dispatcher->dispatch(FOSUserEvents::RESETTING_RESET_INITIALIZE, $event);

    if (null !== $event->getResponse()) {
        return $event->getResponse();
    }


    $form = $formFactory->createForm();
    $form->setData($user);

    $form->handleRequest($request);


    if ($form->isValid()) {
        $event = new FormEvent($form, $request);
        $dispatcher->dispatch(FOSUserEvents::RESETTING_RESET_SUCCESS, $event);


        $userManager->updateUser($user);

        if (null === $response = $event->getResponse()) {
            $url = $this->generateUrl('fos_user_profile_show');
            $response = new RedirectResponse($url);
        }

        $dispatcher->dispatch(FOSUserEvents::RESETTING_RESET_COMPLETED, new FilterUserResponseEvent($user, $request, $response));

        return $response;
    }

    $userManager->updateUser($user);
    return $this->render('FOSUserBundle:Resetting:reset.html.twig', array(
        'token' => $token,
        'form' => $form->createView(),
    ));
}



public function InvalidTokenTtlMessageAction() {
    return $this->render('UserBundle:Resetting:invalidTokenTtlRes.html.twig');
}

public function InvalidTokenClickMessageAction() {
    return $this->render('UserBundle:Resetting:invalidTokenClickRes.html.twig');
}
}