2013-03-06 1 views
11

관리자가 초기 암호를 사용하여 사용자를 생성 할 수있는 Symfony 2.1 프로젝트에 보안 기능을 구현하려고 시도하고 있으며 사용자가 처음으로 변경 암호 처리기가 자동으로 시작될 때 로그인합니다.FOSUserBundle을 사용하여 강제로 비밀번호를 변경하는 방법은 무엇입니까?

FOSUserBundle 클래스를 재정의하는 데 문제가 있습니다. 필자는 어디서나 문서에서 볼 수는 없지만이 기능은 이미 일부 내장되어 있다고 생각합니다.

엔티티에서 credentials_expired 플래그를 사용하고 싶습니다. 관리자가 사용자를 생성하면이 값은 1로 설정됩니다. 사용자가 처음 로그인하면 credentials_expired가 확인되고 예외를 발생시키지 않고 change-password가 실행됩니다. 나는 지금까지 그것을 만들었다.

ChangePasswordController는 암호가 실제로 변경되었는지 확인합니다 (FOS의 기본 동작처럼 보이지 않음). 그리고 credentials_expired가 0으로 설정되었습니다. 이것이 내가 갇혀있는 곳입니다. 서비스의 층이 너무 많아서 적절하게 맞춤 설정된 것을 얻을 수없는 것처럼 보입니다.

+0

좀 더 구체적으로 알려주시겠습니까? 이것을 해결할 수있는 방법이 많이 있습니다. 코드를 게시하면 진행 방법을 식별하는 데 도움이됩니다. 어쨌든, 플래그보다 역할을 많이 사용하는 것은 좋은 생각 일 수 있습니다. 왜냐하면 심포니 방화벽으로 관리 할 수 ​​있기 때문입니다. 따라서 CREDENTIAL_EXPIRED 역할을 담당하는 사용자는 전체 웹에 액세스 할 수 없으며 비밀번호 변경을 요구하는 양식에 갇혀 있습니다. – Manu

+0

코드는 FOSUserBundle입니다. 이 역할은 수업을 연장 할 필요가 없으므로 훌륭한 아이디어입니다. 나는 그 기회를 줄 것이다. 감사. – David

답변

12

자세한 답변입니다. 발판에 대한 감사 마누! ,

"friendsofsymfony/user-bundle":"dev-master" 

다음은 내 자신의 사용자 번들에 포함되어 있습니다 :

첫째, composer.json 파일에 올바른 FOSUserBundle를 얻기 위해 (NOT "*" "DEV-마스터"를) 확인 이것은 설치 문서의 지시에 따라 FOSUserBundle을 확장합니다.

PortalFlare/번들/UserBundle/자원/설정/services.xml 파일 :

<container xmlns="http://symfony.com/schema/dic/services" 
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
xsi:schemaLocation="http://symfony.com/schema/dic/services http://symfony.com/schema/dic/services/services-1.0.xsd"> 

<parameters> 
    <parameter key="portal_flare_user.forcepasswordchange.class">PortalFlare\Bundle\UserBundle\EventListener\ForcePasswordChange</parameter> 
    <parameter key="portal_flare_user.passwordchangelistener.class">PortalFlare\Bundle\UserBundle\EventListener\PasswordChangeListener</parameter> 
</parameters> 

<services> 
    <service id="portal_flare_user.forcepasswordchange" class="%portal_flare_user.forcepasswordchange.class%"> 
     <argument type="service" id="router" /> 
     <argument type="service" id="security.context" /> 
     <argument type="service" id="session" /> 
     <tag name="kernel.event_listener" event="kernel.request" method="onCheckStatus" priority="1" /> 
    </service> 
    <service id="portal_flare_user.passwordchange" class="%portal_flare_user.passwordchangelistener.class%"> 
     <argument type="service" id="router" /> 
     <argument type="service" id="security.context" /> 
     <argument type="service" id="fos_user.user_manager" /> 
     <tag name="kernel.event_subscriber" /> 
    </service> 
</services> 

</container> 

PortalFlare/번들/UserBundle /의 EventListener/ForcePasswordChange.php :

<?php 

namespace PortalFlare\Bundle\UserBundle\EventListener; 

use Symfony\Component\HttpFoundation\RedirectResponse; 
use Symfony\Component\HttpKernel\Event\GetResponseEvent; 

use Symfony\Component\Security\Core\SecurityContext; 
use Symfony\Bundle\FrameworkBundle\Routing\Router; 
use Symfony\Component\HttpFoundation\Session\Session; 

/** 
* @Service("request.set_messages_count_listener") 
* 
*/ 
class ForcePasswordChange { 

    private $security_context; 
    private $router; 
    private $session; 

    public function __construct(Router $router, SecurityContext $security_context, Session $session) { 
    $this->security_context = $security_context; 
    $this->router   = $router; 
    $this->session   = $session; 

    } 

    public function onCheckStatus(GetResponseEvent $event) { 

    if (($this->security_context->getToken()) && ($this->security_context->isGranted('IS_AUTHENTICATED_FULLY'))) { 

     $route_name = $event->getRequest()->get('_route'); 

     if ($route_name != 'fos_user_change_password') { 

     if ($this->security_context->getToken()->getUser()->hasRole('ROLE_FORCEPASSWORDCHANGE')) { 

      $response = new RedirectResponse($this->router->generate('fos_user_change_password')); 
      $this->session->setFlash('notice', "Your password has expired. Please change it."); 
      $event->setResponse($response); 

     } 

     } 

    } 

    } 

} 

PortalFlare/번들/UserBundle/EventListener/PasswordChangeListener.php :

<?php 
namespace PortalFlare\Bundle\UserBundle\EventListener; 

use FOS\UserBundle\FOSUserEvents; 
use FOS\UserBundle\Event\FormEvent; 
use FOS\UserBundle\Doctrine\UserManager; 
use Symfony\Component\EventDispatcher\EventSubscriberInterface; 
use Symfony\Component\HttpFoundation\RedirectResponse; 
use Symfony\Component\Routing\Generator\UrlGeneratorInterface; 
use Symfony\Component\Security\Core\SecurityContext; 

/** 
* Listener responsible to change the redirection at the end of the password change 
*/ 
class PasswordChangeListener implements EventSubscriberInterface { 
    private $security_context; 
    private $router; 
    private $usermanager; 

    public function __construct(UrlGeneratorInterface $router, SecurityContext $security_context, UserManager $usermanager) { 
    $this->security_context = $security_context; 
    $this->router   = $router; 
    $this->usermanager  = $usermanager; 
    } 

    /** 
    * {@inheritDoc} 
    */ 
    public static function getSubscribedEvents() { 
    return array(
     FOSUserEvents::CHANGE_PASSWORD_SUCCESS => 'onChangePasswordSuccess', 
    ); 
    } 

    public function onChangePasswordSuccess(FormEvent $event) { 

    $user = $this->security_context->getToken()->getUser(); 
    $user->removeRole('ROLE_FORCEPASSWORDCHANGE'); 
    $this->usermanager->updateUser($user); 

    $url = $this->router->generate('_welcome'); 
    $event->setResponse(new RedirectResponse($url)); 
    } 
} 

FOSUserBundle의 문제로 인해 사용자가 암호를 변경하는 것이 실제로 확인되지 않은 것은 다른 날의 문제입니다.

이 정보가 도움이되기를 바랍니다.

4

좋은 접근법은 전체 앱에 액세스 할 수있는 역할을하는 ROLE_USER를 정의하기 시작할 수 있습니다. 사용자가 등록하면 자동으로 ROLE_CREDENTIAL_EXPIRED 또는 이와 유사한 항목이 추가됩니다. JMSSecurityExtraBundle을 사용하면 컨트롤러에 주석을 사용하여 주어진 역할을 가진 사용자가 액세스 할 수 있는지 여부를 결정할 수 있습니다. 또한 Symfony handle the HTTP Authentication의 문서를 확인하십시오.

+0

가난한 @Manu 내가 생각하는 upvote받을 가치가있어 :) –

+0

그건 당신에게 아주 친절 해요! 고맙습니다 @ DarraghEnright :) – Manu