2013-05-30 4 views
0

Я новичок в Symfony2 и сталкиваюсь с проблемой с той недели, когда мне нужно реализовать пользовательскую аутентификацию. Мне удалось создать все, т. Е. Токен, слушатель, поставщик, завод, поставщик и т. Д. Моя проблема в том, что после проверки подлинности я не смог увидеть правильный токен. Я думаю, что UserPasswordProvider (предоставленный symfony2) все еще работает после аутентификации и refreshUser в провайдере пользователя показывает мне неправильный токен. Я стараюсь искать почти везде, но не могу решить эту проблему. Нужна помощь/намек на это, если кто-нибудь знает. Благодарю.Symfony2 - Неверный токен после аутентификации

Вот изображение (http://tinypic.com/r/33bl5l0/5) неправильного токена. Это должно быть ADWSUserToken

Ниже приведен код. Я использую Symfony 2.2.0

ADWSUserToken.php

namespace StudentIntranet\GenericBundle\Security\Authentication\Token; 

use Symfony\Component\Security\Core\Authentication\Token\AbstractToken; 

class ADWSUserToken extends AbstractToken 
{ 
    public $userObjectType = ""; 
    public $password = ""; 

    public function getCredentials() 
    { 
     return ''; 
    } 
} 

ADWSListener.php

namespace StudentIntranet\GenericBundle\Security\Firewall; 

use Symfony\Component\HttpFoundation\Response; 
use Symfony\Component\HttpKernel\Event\GetResponseEvent; 
use Symfony\Component\Security\Http\Firewall\ListenerInterface; 
use Symfony\Component\Security\Http\HttpUtils; 
use Symfony\Component\Security\Core\Exception\AuthenticationException; 
use Symfony\Component\Security\Core\SecurityContextInterface; 
use Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface; 

use StudentIntranet\GenericBundle\Security\Authentication\Token\ADWSUserToken; 

class ADWSListener implements ListenerInterface 
{ 
    protected $securityContext; 
    protected $authenticationManager; 
    protected $providerKey; 

    public function __construct(SecurityContextInterface $securityContext, AuthenticationManagerInterface $authenticationManager) 
    { 
     $this->securityContext = $securityContext; 
     $this->authenticationManager = $authenticationManager; 
    } 

    public function handle(GetResponseEvent $event) 
    { 
     $httpUtils = new HttpUtils(); 
     $request = $event->getRequest(); 
     $form = $request->request->get('form'); 
     foreach (array('_token', 'username', 'password') as $val) { 
      $$val = isset($form[$val]) ? $form[$val] : ""; 
     } 
     $remember_me = isset($form['remember_me']) ? $form['remember_me'] : "Off"; 

     if (!$username || !$password) { 
      return; 
     } 

     $token = new ADWSUserToken(); 
     $token->setUser($username); 
     $token->password = $password; 

     try { 
      $authToken = $this->authenticationManager->authenticate($token); 
      $this->securityContext->setToken($authToken); 
     } catch (AuthenticationException $failed) { 
      $this->securityContext->setToken(null); 
      $event->setResponse($httpUtils->createRedirectResponse($request, '/login')); 
      return; 
     } 

     // By default deny authorization 
//  $response = new Response('NO'); 
//  $response->setStatusCode(403); 
//  $event->setResponse($response); 
    } 
} 

ADWSProvider.php

namespace StudentIntranet\GenericBundle\Security\Authentication\Provider; 

use Symfony\Component\Security\Core\Authentication\Provider\AuthenticationProviderInterface; 
use Symfony\Component\Security\Core\User\UserProviderInterface; 
use Symfony\Component\Security\Core\Exception\AuthenticationException; 
use Symfony\Component\Security\Core\Exception\NonceExpiredException; 
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; 

use StudentIntranet\GenericBundle\Security\Authentication\Token\ADWSUserToken; 

class ADWSProvider implements AuthenticationProviderInterface 
{ 
    private $userProvider; 

    public function __construct(UserProviderInterface $userProvider) 
    { 
     $this->userProvider = $userProvider; 
    } 

    public function authenticate(TokenInterface $token) 
    { 
     $username = $token->getUser(); 
     $password = $token->password; 

     // here I need to load info using web service ... 

     if ($username == 'admin' && $password == 'testadmin') { 
      $token->userObjectType = "User-Staff-MSC"; 
     } elseif ($username == 'user' && $password == 'testuser') { 
      $token->userObjectType = "User-Participant-MSC"; 
     } 

     $userObjectTypes = explode("-", $token->userObjectType); 
     $allowedEntites = array('Staff', 'Participant'); 

     $roles = array(
      'Participant' => 'ROLE_USER', 
      'Staff' => 'ROLE_ADMIN' 
     ); 

     if (count($userObjectTypes) >= 2 && in_array($userObjectTypes[1], $allowedEntites)) { 
      $tmp = $this->userProvider->loadUserByUsername($token->getUsername()); 
      $role = $roles[$userObjectTypes[1]]; 
      $authToken = new ADWSUserToken(array($role)); 
      $authToken->setUser($username); 
      $authToken->userObjectType = $token->userObjectType; 
      $authToken->setAuthenticated(true); 

      return $authToken; 
     } 

     //$user = $this->userProvider->loadUserByUsername($token->getUsername()); 

     throw new AuthenticationException('The ADWS authentication failed.'); 
    } 

    public function supports(TokenInterface $token) 
    { 
     return $token instanceof ADWSUserToken; 
    } 
} 

ADWSFactory.php

namespace StudentIntranet\GenericBundle\DependencyInjection\Security\Factory; 

use Symfony\Component\DependencyInjection\ContainerBuilder; 
use Symfony\Component\DependencyInjection\Reference; 
use Symfony\Component\DependencyInjection\DefinitionDecorator; 
use Symfony\Component\Config\Definition\Builder\NodeDefinition; 
use Symfony\Bundle\SecurityBundle\DependencyInjection\Security\Factory\SecurityFactoryInterface; 

class ADWSFactory implements SecurityFactoryInterface 
{ 
    public function create(ContainerBuilder $container, $id, $config, $userProvider, $defaultEntryPoint) 
    { 
     $providerId = 'security.authentication.provider.adws.'.$id; 
     $container 
      ->setDefinition($providerId, new DefinitionDecorator('adws.security.authentication.provider')) 
      ->replaceArgument(0, new Reference($userProvider)) 
     ; 

     $listenerId = 'security.authentication.listener.adws.'.$id; 
     $listener = $container 
      ->setDefinition($listenerId, new DefinitionDecorator('adws.security.authentication.listener')) 
     ; 

     return array($providerId, $listenerId, $defaultEntryPoint); 
    } 

    public function getPosition() 
    { 
     return 'pre_auth'; 
    } 

    public function getKey() 
    { 
     return 'adws'; 
    } 

    public function addConfiguration(NodeDefinition $node) 
    { 
    } 
} 

ADWSUser.php

namespace StudentIntranet\GenericBundle\Security\User; 
use Symfony\Component\Security\Core\User\UserInterface; 
use Symfony\Component\Security\Core\User\EquatableInterface; 
class ADWSUser implements UserInterface, EquatableInterface 
{ 
    private $username; 
    private $password; 
    private $salt; 
    private $roles; 
    public function __construct($username, $password, $salt, array $roles) 
    { 
     $this->username = $username; 
     $this->password = $password; 
     $this->salt = $salt; 
     $this->roles = $roles; 
    } 
    public function getRoles() 
    { 
     return $this->roles; 
    } 
    public function getPassword() 
    { 
     return $this->password; 
    } 
    public function getSalt() 
    { 
     return $this->salt; 
    } 
    public function getUsername() 
    { 
     return $this->username; 
    } 
    public function eraseCredentials() 
    { 
    } 
    public function isEqualTo(UserInterface $user) 
    { 
     if (!$user instanceof ADWSUser) { 
      return false; 
     } 
     if ($this->password !== $user->getPassword()) { 
      return false; 
     } 
     if ($this->getSalt() !== $user->getSalt()) { 
      return false; 
     } 
     if ($this->username !== $user->getUsername()) { 
      return false; 
     } 
     return true; 
    } 
} 

ADWSUserProvider.php

namespace StudentIntranet\GenericBundle\Security\User; 

use Symfony\Component\Security\Core\User\UserProviderInterface; 
use Symfony\Component\Security\Core\User\UserInterface; 
use Symfony\Component\Security\Core\Exception\UsernameNotFoundException; 
use Symfony\Component\Security\Core\Exception\UnsupportedUserException; 

class ADWSUserProvider implements UserProviderInterface 
{ 
    public function loadUserByUsername($username) 
    { 
     return new ADWSUser($username, '', '', array('ROLE_USER')); 
    } 

    public function refreshUser(UserInterface $user) 
    { 
     return $user; 
    } 

    public function supportsClass($class) 
    { 
     return $class === 'StudentIntranet\GenericBundle\Security\User\ADWSUser'; 
    } 
} 

StudentIntranetGenericBundle.php

namespace StudentIntranet\GenericBundle; 

use StudentIntranet\GenericBundle\DependencyInjection\Security\Factory\ADWSFactory; 
use Symfony\Component\HttpKernel\Bundle\Bundle; 
use Symfony\Component\DependencyInjection\ContainerBuilder; 

class StudentIntranetGenericBundle extends Bundle 
{ 
    public function build(ContainerBuilder $container) 
    { 
     parent::build($container); 

     $extension = $container->getExtension('security'); 
     $extension->addSecurityListenerFactory(new ADWSFactory()); 
    } 
} 

config.yml

imports: 
    - { resource: parameters.yml } 
    - { resource: security.yml } 
    - { resource: "@StudentIntranetGenericBundle/Resources/config/services.yml" } 

framework: 
    #esi:    ~ 
    #translator:  { fallback: %locale% } 
    secret:   %secret% 
    router: 
     resource: "%kernel.root_dir%/config/routing.yml" 
     strict_requirements: %kernel.debug% 
    form:   ~ 
    csrf_protection: ~ 
    validation:  { enable_annotations: true } 
    templating: 
     engines: ['twig'] 
     #assets_version: SomeVersionScheme 
    default_locale: "%locale%" 
    trusted_proxies: ~ 
    session:   ~ 
    fragments:  ~ 

# Twig Configuration 
twig: 
    debug:   %kernel.debug% 
    strict_variables: %kernel.debug% 

# Assetic Configuration 
assetic: 
    debug:   %kernel.debug% 
    use_controller: false 
    bundles:  [ ] 
    #java: /usr/bin/java 
    filters: 
     cssrewrite: ~ 
     #closure: 
     # jar: %kernel.root_dir%/Resources/java/compiler.jar 
     #yui_css: 
     # jar: %kernel.root_dir%/Resources/java/yuicompressor-2.4.7.jar 

# Doctrine Configuration 
doctrine: 
    dbal: 
     driver: %database_driver% 
     host:  %database_host% 
     port:  %database_port% 
     dbname: %database_name% 
     user:  %database_user% 
     password: %database_password% 
     charset: UTF8 
     # if using pdo_sqlite as your database driver, add the path in parameters.yml 
     # e.g. database_path: %kernel.root_dir%/data/data.db3 
     # path:  %database_path% 

    orm: 
     auto_generate_proxy_classes: %kernel.debug% 
     auto_mapping: true 

# Swiftmailer Configuration 
swiftmailer: 
    transport: %mailer_transport% 
    host:  %mailer_host% 
    username: %mailer_user% 
    password: %mailer_password% 
    spool:  { type: memory } 

Главный routing.yml

student_intranet_student: 
    resource: "@StudentIntranetStudentBundle/Resources/config/routing.yml" 
    prefix: /student/ 

student_intranet_admin: 
    resource: "@StudentIntranetAdminBundle/Resources/config/routing.yml" 
    prefix: /admin/ 

student_intranet_generic: 
    resource: "@StudentIntranetGenericBundle/Resources/config/routing.yml" 
    prefix: /

student_intranet_empty: 
    resource: "@StudentIntranetEmptyBundle/Resources/config/routing.yml" 
    prefix: /empty/ 

security.yml

jms_security_extra: 
    secure_all_services: false 
    expressions: true 

security: 
    encoders: 
     #Symfony\Component\Security\Core\User\User: plaintext 
     StudentIntranet\GenericBundle\Security\User\ADWSUser: plaintext 

    role_hierarchy: 
     ROLE_ADMIN:  [ROLE_USER, ROLE_ALLOWED_TO_SWITCH] 
     #ROLE_ADMIN:  ROLE_USER 
     #ROLE_SUPER_ADMIN: [ROLE_USER, ROLE_ADMIN, ROLE_ALLOWED_TO_SWITCH] 

    providers: 
     #chain_provider: 
     # chain: 
     #  providers: in_memory #[user_provider, in_memory] 
     user_provider: 
      id: adws.user.provider 
     #in_memory: 
     # memory: 
     #  users: 
     #   user: { password: userpass, roles: [ 'ROLE_USER' ] } 
     #   admin: { password: adminpass, roles: [ 'ROLE_ADMIN' ] } 
     #   superadmin: { password: superadminpass, roles: [ 'ROLE_SUPER_ADMIN' ] } 

    firewalls: 
     dev: 
      pattern: ^/(_(profiler|wdt)|css|images|js)/ 
      security: false 

     free_area: 
      pattern: ^/default/ 
      anonymous: ~ 

     login: 
      pattern: ^/login$ 
      security: false 

     secured_area: 
      pattern: ^/ 
      adws: true 
      form_login: 
       provider:    user_provider 
       check_path:    login_check 
       login_path:    login 
      logout: 
       path: logout 
       target:/
      switch_user: true 

    access_control: 
     - { path: ^/login, roles: IS_AUTHENTICATED_ANONYMOUSLY } #, requires_channel: https 
     - { path: ^/student/, roles: ROLE_USER } 
     - { path: ^/admin, roles: ROLE_ADMIN } 
     #- { path: ^/empty, roles: ROLE_SUPER_ADMIN } 

GenericBundle routing.yml

root: 
    path: /
    defaults: 
     _controller: FrameworkBundle:Redirect:urlRedirect 
     path: /student/ 

login: 
    pattern: /login 
    defaults: { _controller: StudentIntranetGenericBundle:Security:login } 

login_check: 
    pattern: /login_check 
    #defaults: { _controller: StudentIntranetGenericBundle:Security:loginCheck } 

logout: 
    pattern: /logout 
    defaults: { _controller: StudentIntranetGenericBundle:Security:logout } 

generic_homepage: 
    pattern: /generic 
    defaults: { _controller: StudentIntranetGenericBundle:Default:index } 

GenericBundle services.yml

parameters: 
# student_intranet_generic.example.class: StudentIntranet\GenericBundle\Example 

services: 
# student_intranet_generic.example: 
#  class: %student_intranet_generic.example.class% 
#  arguments: [@service_id, "plain_value", %parameter%] 

    adws.user.provider: 
     class: StudentIntranet\GenericBundle\Security\User\ADWSUserProvider 

    adws.security.authentication.provider: 
     class: StudentIntranet\GenericBundle\Security\Authentication\Provider\ADWSProvider 
     arguments: [""] 

    adws.security.authentication.listener: 
     class: StudentIntranet\GenericBundle\Security\Firewall\ADWSListener 
     arguments: ["@security.context", "@security.authentication.manager"] 

SecurityController.PHP

namespace StudentIntranet\GenericBundle\Controller; 

use Symfony\Bundle\FrameworkBundle\Controller\Controller; 
use Symfony\Component\Security\Core\SecurityContext; 
use Symfony\Component\Validator\Constraints\NotBlank; 
//use Symfony\Component\HttpFoundation\Request; 

class SecurityController extends Controller 
{ 
    public function loginAction() 
    { 
     $request = $this->getRequest(); 
     $session = $request->getSession(); 
     $authError = SecurityContext::AUTHENTICATION_ERROR; 

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

     $form = $this->createFormBuilder(array()) 
      ->add('username', 'text', array(
       'constraints' => new NotBlank(), 
       )) 
      ->add('password', 'password', array(
       'constraints' => new NotBlank(), 
       )) 
      //->add('remember_me', 'checkbox', array(
      // 'value' => 'On', 
      // 'required' => false, 
      // )) 
      ->getForm(); 

     return $this->render(
      'StudentIntranetGenericBundle:Login:index.html.twig', 
      array(
       // last username entered by the user 
       'last_username' => $session->get(SecurityContext::LAST_USERNAME), 
       'error' => $error, 
       'form' => $form->createView() 
      ) 
     ); 
    } 

    public function loginCheckAction() 
    { 
     // The security layer will intercept this request 
     /* These are not working... 
     if ($this->get('security.context')->isGranted('ROLE_SUPER_ADMIN')) { 
      // ... load admin content here 
      return $this->redirect($this->generateUrl('student_intranet_empty', array('name' => 'Super Admin'))); 
     } elseif ($this->get('security.context')->isGranted('ROLE_ADMIN')) { 
      // ... load admin content here 
      return $this->redirect($this->generateUrl('student_intranet_admin', array('name' => 'Admin'))); 
     } else { 
      // ... load admin content here 
      return $this->redirect($this->generateUrl('student_intranet_student', array('name' => 'Student'))); 
     } 
     */ 
    } 

    public function logoutAction() 
    { 
     // The security layer will intercept this request 
    } 
} 

index.html.twig

{% extends 'StudentIntranetGenericBundle::layout.html.twig' %} 
{% block content %} 
    {% if error %} 
     <div>{{ error.message }}</div> 
    {% endif %} 
    <form action="{{ path('login_check') }}" method="post"> 
     {# this has CSRF protection #} 
     {{ form_widget(form) }} 

     <button type="submit">login</button> 
    </form> 
{% endblock %} 

ответ

0

Я думаю, что я нашел этот вопрос в слушателе. Нам нужно настроить ответ на событие для перенаправления после успешной аутентификации, иначе слушатели покинут symfony, т. Е. Вступает в действие UserPasswordFormAuthenticationListener.php. Кроме того, мне нужно правильно настроить моего провайдера. Вот файлы, измененные и обработанные для меня.

P.S. Нам также необходимо изменить слушателя для пользователя коммутатора, если нам нужно. Я изменил свой прослушиватель (не показан здесь), чтобы обрабатывать пользователя-переключателя, но ему нужна еще одна конфигурация.

ADWSListener.php

namespace StudentIntranet\GenericBundle\Security\Firewall; 

use Symfony\Component\HttpFoundation\Response; 
use Symfony\Component\HttpKernel\Event\GetResponseEvent; 
use Symfony\Component\Security\Http\Firewall\ListenerInterface; 
use Symfony\Component\Security\Http\HttpUtils; 
use Symfony\Component\Security\Core\Exception\AuthenticationException; 
use Symfony\Component\Security\Core\SecurityContextInterface; 
use Symfony\Component\Security\Core\Authentication\AuthenticationManagerInterface; 

use StudentIntranet\GenericBundle\Security\Authentication\Token\ADWSUserToken; 

class ADWSListener implements ListenerInterface 
{ 
    protected $securityContext; 
    protected $authenticationManager; 
    protected $providerKey; 

    public function __construct(SecurityContextInterface $securityContext, AuthenticationManagerInterface $authenticationManager) 
    { 
     $this->securityContext = $securityContext; 
     $this->authenticationManager = $authenticationManager; 
    } 

    public function handle(GetResponseEvent $event) 
    { 
     $request = $event->getRequest(); 
     $httpUtils = new HttpUtils(); 

     $form = $request->request->get('form'); 
     foreach (array('_token', 'username', 'password') as $val) { 
      $$val = isset($form[$val]) ? $form[$val] : ""; 
     } 
     $remember_me = isset($form['remember_me']) ? $form['remember_me'] : "Off"; 

     if (!$username || !$password) { 
      return; 
     } 

     $token = new ADWSUserToken(); 
     $token->setUser($username); 
     $token->password = $password; 

     try { 
      $authToken = $this->authenticationManager->authenticate($token); 
      $this->securityContext->setToken($authToken); 
      $event->setResponse($httpUtils->createRedirectResponse($request, '/')); 
      return; 
     } catch (AuthenticationException $failed) { 
      $this->securityContext->setToken(null); 
      //$event->setResponse($httpUtils->createRedirectResponse($request, '/login')); 
      return; 
     } 

     // By default deny authorization 
//  $response = new Response('NO'); 
//  $response->setStatusCode(403); 
//  $event->setResponse($response); 
    } 

} 

ADWSUserProvider.php

namespace StudentIntranet\GenericBundle\Security\User; 

use Symfony\Component\Security\Core\User\UserProviderInterface; 
use Symfony\Component\Security\Core\User\UserInterface; 
use Symfony\Component\Security\Core\Exception\UsernameNotFoundException; 
use Symfony\Component\Security\Core\Exception\UnsupportedUserException; 

class ADWSUserProvider implements UserProviderInterface 
{ 
    public function loadUserByUsername($username) 
    { 
     // here I need to load info using web service ... 

     if ($username == 'user') { 
      return new ADWSUser($username, '', null, array('ROLE_USER')); 
     } elseif ($username == 'admin') { 
      return new ADWSUser($username, '', null, array('ROLE_ADMIN')); 
     } 

     throw new UsernameNotFoundException(sprintf('Username "%s" does not exist.', $username)); 
    } 

    public function refreshUser(UserInterface $user) 
    { 
     if (!$user instanceof ADWSUser) { 
      throw new UnsupportedUserException(sprintf('Instances of "%s" are not supported.', get_class($user))); 
     } 

     return $this->loadUserByUsername($user->getUsername()); 

    } 

    public function supportsClass($class) 
    { 
     return $class === 'StudentIntranet\GenericBundle\Security\User\ADWSUser'; 
    } 
} 
Смежные вопросы