2015-05-27 89 views
1

我需要基於Symfony2創建一個基於我的網站的身份驗證系統。我遵循that tutorial(法語),它解釋瞭如何認證用戶以及如何登錄它們。問題是我的認證系統不能使用從頭構建的用戶實體,因爲我的目標是在不改變數據庫結構的情況下重構網站。如何使用現有數據庫的數據驗證用戶?

這是我從數據庫生成的用戶實體。這是一個有點棘手,因爲我需要一個類來實現的UserInterface,所以我手動添加getUsername,getSalt和eraseCredetials方法:

namespace GEAP\UserBundle\Entity; 

use Doctrine\ORM\Mapping as ORM; 
use Symfony\Component\Security\Core\User\UserInterface; 

class User implements UserInterface { 
    private $login; 
    private $password; 
    private $lastname; 
    private $firstname; 
    private $roles; 
    private $restrictionsIp; 
    private $idPage; 


    public function __construct() 
    { 
     $this->idPage = new \Doctrine\Common\Collections\ArrayCollection(); 
    } 

    public function getLogin() 
    { 
     return $this->login; 
    } 

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

    public function setPassword($password) 
    { 
     $this->password = $password; 

     return $this; 
    } 

    public function getPassword() 
    { 
     return $this->password; 
    } 

    public function getSalt() 
    { 
     return "md5"; 
    } 

    public function setLastname($lastname) 
    { 
     $this->lastname = $lastname; 

     return $this; 
    } 

    public function getLastname() 
    { 
     return $this->lastname; 
    } 

    public function setFirstname($firstname) 
    { 
     $this->firstname = $firstname; 

     return $this; 
    } 

    public function getFirstname() 
    { 
     return $this->firstname; 
    } 


    public function setRoles($roles) 
    { 
     $this->roles = $roles; 

     return $this; 
    } 

    public function getRoles() 
    { 
     return $this->roles; 
    } 

    public function setRestrictionsIp($restrictionsIp) 
    { 
     $this->restrictionsIp = $restrictionsIp; 

     return $this; 
    } 


    public function getRestrictionsIp() 
    { 
     return $this->restrictionsIp; 
    } 


    public function addIdPage(\GEAP\IntranetBundle\Entity\Pages $idPage) 
    { 
     $this->idPage[] = $idPage; 

     return $this; 
    } 

    public function removeIdPage(\GEAP\IntranetBundle\Entity\Pages $idPage) 
    { 
     $this->idPage->removeElement($idPage); 
    } 

    public function getIdPage() 
    { 
     return $this->idPage; 
    } 

    public function eraseCredentials() {} 
} 

這裏是我的security.yml:

# app/config/security.yml 

security: 
    encoders: 
     Symfony\Component\Security\Core\User\User: plaintext 
     GEAP\UserBundle\Entity\User: md5 

    role_hierarchy: 
     ROLE_ADMIN:  [ROLE_ENS, ROLE_ETU, ROLE_SEC] 
     ROLE_SUPER_ADMIN: [ROLE_ENS, ROLE_ETU, ROLE_SEC, ROLE_ADMIN, ROLE_ALLOWED_TO_SWITCH] 

    providers: 
     in_memory: 
      memory: 
       users: 
        user_ens: { password: userpass, roles: [ 'ROLE_ENS' ] } 
        user_etu: { password: userpass, roles: [ 'ROLE_ETU' ] } 
        user_sec: { password: userpass, roles: [ 'ROLE_SEC' ] } 
        admin: { password: adminpass, roles: [ 'ROLE_ADMIN' ] } 
     main: 
      entity: { class: GEAP\UserBundle\Entity\User, property: login } 

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

     main_login: 
      pattern: ^/$ 
      anonymous: true 

     main: 
      pattern: ^/ 
      anonymous: false 
     # provider: main 
      provider: in_memory 
      form_login: 
       login_path: login 
       check_path: login_check 
       always_use_default_target_path: true 
       default_target_path: /home 
      logout: 
       path: logout 
       target:/

    access_control: 
     #- { path: ^/login, roles: IS_AUTHENTICATED_ANONYMOUSLY, requires_channel: https } 

這裏是我SecurityController:

namespace GEAP\UserBundle\Controller; 

use Symfony\Bundle\FrameworkBundle\Controller\Controller; 
use Symfony\Component\HttpFoundation\Request; 
use Symfony\Component\Security\Core\SecurityContext; 

class SecurityController extends Controller { 

    public function loginAction(Request $request) { 

    // Si le visiteur est déjà identifié, on le redirige vers l'accueil 
    if ($this->get('security.context')->isGranted('IS_AUTHENTICATED_REMEMBERED')) { 
     return $this->redirect($this->generateUrl('geap_intranet_customhomepage')); 
    } 

    $session = $request->getSession(); 

    // On vérifie s'il y a des erreurs d'une précédente soumission du formulaire 
    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); 
    } 

    return $this->render('GEAPUserBundle:Security:login.html.twig', array(
     // Valeur du précédent nom d'utilisateur entré par l'internaute 
     'last_username' => $session->get(SecurityContext::LAST_USERNAME), 
     'error'   => $error, 
    )); 
    } 

} 

當我取消了安全性:防火牆:主營:供應商:爲主線,whend我嘗試登錄我的網站,我的憑據(這是在d atabase),則會顯示以下錯誤消息:

憑據無效。

你知道問題出在哪裏嗎?

+0

你有沒有實現序列化()方法?我認爲這是強制性的認證工作 – Hakim

+0

serialize()方法?我應該在哪裏實施它,目的是什麼? – Lyudline

回答

0

我建議創建一個不同的編碼器:

encoders: 
    Symfony\Component\Security\Core\User\User: 
     algorithm: sha1 
     iterations: 1 
     encode_as_base64: false 

,創造登錄檢查方法:

public function loginCheckAction(Request $request){ 
    /** @var Session $session */ 
    $session = $request->getSession(); 
    $username = $request->get('_username'); 
    $password = $request->get('_password'); 

    $anonymousKey = uniqid(); 
    $passwordEncoder = new Pbkdf2PasswordEncoder(); 
    $inMemoryUserProvider = new InMemoryUserProvider(); 
    $userChecker = new UserChecker(); 

    $encoderFactory = new EncoderFactory(array(
     'Symfony\Component\Security\Core\User\User' => $passwordEncoder 
    )); 

    $authenticationProviders = array(
     // validates AnonymousToken instances 
     new AnonymousAuthenticationProvider($anonymousKey), 
     // retrieve the user for a UsernamePasswordToken 
     new DaoAuthenticationProvider($inMemoryUserProvider, $userChecker, 'main', $encoderFactory) 
    ); 
    $authenticationManager = new AuthenticationProviderManager($authenticationProviders); 


    $accessDecisionManager = new AccessDecisionManager([new RoleVoter('ROLE_ADMIN')]); 
    $securityContext = new SecurityContext($authenticationManager, $accessDecisionManager); 

    try { 
     $usernamePasswordToken = new UsernamePasswordToken($username, $password, 'main'); 
     $authenticationManager->authenticate($usernamePasswordToken); 
     $securityContext->setToken($usernamePasswordToken); 

     if ($securityContext->isGranted('ROLE_ADMIN')) { 
      /** @var TokenStorage $tokenStorage */ 
      $tokenStorage = $this->get('security.token_storage'); 
      $tokenStorage->setToken($usernamePasswordToken); 

      return $this->redirectToRoute('index'); 

     } else { 
      $session->getFlashBag()->add('error', 'Access denied. Invalid credentials'); 
     } 
    } catch (BadCredentialsException $e) { 
     $session->getFlashBag()->add('error', 'Invalid username or password'); 
    } catch (ProviderNotFoundException $e) { 
     $session->getFlashBag()->add('error', 'Provider could not be found'); 
    } 

    return $this->redirectToRoute('login'); 
} 
+0

我試圖應用您的建議,但沒有奏效。現在錯誤是_Authentication請求由於系統問題而無法處理._ – Lyudline

相關問題