如何使用现有数据库的数据验证用户?

时间:2015-05-27 13:18:54

标签: php security symfony authentication symfony-2.3

我需要在我的网站上创建一个基于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,
    ));
  }

}

当我取消注释安全性时:firewalls:main:provider:main line,当我尝试使用我的凭据(在数据库中)登录我的网站时,会出现该错误消息:

  

凭据无效。

你知道问题的来源吗?

1 个答案:

答案 0 :(得分: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');
}