-->

Silex security provider

2020-07-24 04:39发布

问题:

I have a class UserMapper

<?php

namespace Models;

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


class UserMapper implements UserProviderInterface
{
/**
* Database connection.
*/
var $db = NULL;


/**
* Constructor function. Loads model from database if the id is known.
*
* @param $db
*   Database connection
*/
function __construct() {    
    $this->db = ConnectionProvider::getConnection();
}


function save(User $user) {
    $statement = $this->db->prepare('INSERT INTO user (username, password, salt, roles) VALUES (:username, :password, :salt, :roles)');
    foreach (array('username', 'password', 'salt', 'roles') as $property) {
        $placeholders[':' . $property] = $user->get($property);
    }
    $isOk = $statement->execute($placeholders);        
    return $isOk;
}


public function findByUsername($username) {
    $statement = $this->db->prepare('SELECT * FROM user WHERE username = :username');
    $statement->execute(array(':username' => $username));
    $data = $statement->fetch(PDO::FETCH_ASSOC);
    if($data['username'] == null)
        return null;
    else {
        $user = new User($data['username'], $data['salt'], $data['roles']);
        $user->set('password', $data['password']);
        return $user;
    }
}

function loadAll() {

    // Query for the existing users.
    $statement = $this->db->query('SELECT * FROM user');
    $results = $statement->fetchAll(PDO::FETCH_ASSOC);

    // Format the list and output it as JSON.
    $data = array();
    foreach ($results as $result) {
        $user = new User($result['username'], $result['salt'], $result['roles']);
        $user->set('passwort', $result['password']);

        $data[] = $user;
    }

    return $data;
  }

    /**
   * Delete this user.
   */
  function delete(User $user) {
    if ($user->get('username')) {
      // Execute the delete query.
      $statement = $this->db->prepare('DELETE FROM user WHERE username = :username');
      $statement->execute(array(':username' => $user->get('username')));
    }
  }

  /// UserProviderInterface
  public function loadUserByUsername($username)
  {
    $user = $this->findByUsername($username);

    if($user == null)
        throw new UsernameNotFoundException(sprintf('Username "%s" does not exist.', $username));

    return $user;
  }

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

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

  public function supportsClass($class)
  {
    return $class === 'Models\User';
  }
  }

and my class User

<?php

namespace Models;

use Symfony\Component\Security\Core\User\UserInterface;

class User implements UserInterface{

var $username = NULL;
var $password = NULL;
var $salt = NULL;
var $roles = NULL;

function __construct($username, $password, $sal, $roles) { 
$this->username = $username;
$this->password = $password;  
$this->salt = $salt;  
$this->roles = $roles; 
}

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

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

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

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

function eraseCredentials() {
}

function get($property) {
if (!empty($this->{$property})) {
  return $this->{$property};
}
else {
  return false;
}
}

function set($property, $value) {
$this->{$property} = $value;
}

function getAll() {
return array(
  'username' => $this->get('username'),
  'password' => $this->get('password'),
  'salt' => $this->get('salt'),
  'roles' => $this->get('roles')
);
}
}

And in my index.php I configure the security context like this :

$app['security.firewalls'] = array(
'secured' => array(
    'pattern'    => '^/',
    'anonymous'  => array(),
    'form' => array(
        'login_path' => 'login', 
        'check_path' => 'login_check'
    ),
    'users' => $app->share(function () use ($app) {
        return $app['UserMapper'];
    }),
)
);

$app['security.access_control'] = array(
array('path' => '^/login', 'role' => 'IS_AUTHENTICATED_ANONYMOUSLY'),
array('path' => '^/', 'role' => 'IS_AUTHENTICATED_ANONYMOUSLY'),
array('path' => '^/comment', 'methode' => 'POST', 'role' => 'IS_AUTHENTICATED_ANONYMOUSLY'),
array('path' => '^/comment', 'methode' => 'DELETE', 'role' => 'ROLE_ADMIN'),
array('path' => '^/location', 'methode' => 'GET, POST', 'role' => 'IS_AUTHENTICATED_ANONYMOUSLY'),
array('path' => '^/location', 'methode' => 'PUT, DELETE', 'role' => 'ROLE_ADMIN')    
);

$app['security.provider'] = array(
'users' => array(
    'entity' => array('class' => 'Models\User', 'property' => 'username')
)
);

 $app['security.encoders'] = array(
'Models\User' => array(
    'algorithm' => 'bcrypt',
)
);

$app->register(new UrlGeneratorServiceProvider());
$app->register(new Silex\Provider\SecurityServiceProvider(), array(
'security.firewalls' => $app['security.firewalls'],
'security.access_control' => $app['security.access_control'],
'security.provider' => $app['security.provider'],
'security.encoders' => $app['security.encoders'],
));

The problem is when I submit the login form with a foo login and foo password which don't exist in the database, the security context create me a session.

What is wrong with the security provider ?

回答1:

security.access_control is not defined in Silex\Provider\SecurityServiceProvider. I believe it should be security.access_rules:

$app['security.access_rules'] = array(
    array('^/admin', 'ROLE_ADMIN'),

);