Open lukeman83 opened 11 years ago
you should typehint the UserManagerInterface, not an implementation
I'm using documentation code. Is this not ok?
<?php
// src/project/YourBundle/Security/User/Provider/TwitterUserProvider.php
namespace project\YourBundle\Security\User\Provider;
use Symfony\Component\Security\Core\Exception\UsernameNotFoundException;
use Symfony\Component\Security\Core\Exception\UnsupportedUserException;
use Symfony\Component\Security\Core\User\UserProviderInterface;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\HttpFoundation\Session;
use \TwitterOAuth;
use FOS\UserBundle\Entity\UserManager;
use Symfony\Component\Validator\Validator;
class TwitterUserProvider implements UserProviderInterface
{
/**
* @var \Twitter
*/
protected $twitter_oauth;
protected $userManager;
protected $validator;
protected $session;
public function __construct(TwitterOAuth $twitter_oauth, UserManager $userManager,Validator $validator, Session $session)
{
$this->twitter_oauth = $twitter_oauth;
$this->userManager = $userManager;
$this->validator = $validator;
$this->session = $session;
}
public function supportsClass($class)
{
return $this->userManager->supportsClass($class);
}
public function findUserByTwitterId($twitterID)
{
return $this->userManager->findUserBy(array('twitterID' => $twitterID));
}
public function loadUserByUsername($username)
{
$user = $this->findUserByTwitterId($username);
$this->twitter_oauth->setOAuthToken($this->session->get('access_token'), $this->session->get('access_token_secret'));
try {
$info = $this->twitter_oauth->get('account/verify_credentials');
} catch (Exception $e) {
$info = null;
}
if (!empty($info)) {
if (empty($user)) {
$user = $this->userManager->createUser();
$user->setEnabled(true);
$user->setPassword('');
$user->setAlgorithm('');
}
$username = $info->screen_name;
$user->setTwitterID($info->id);
$user->setTwitterUsername($username);
$user->setEmail('');
$user->setFirstname($info->name);
$this->userManager->updateUser($user);
}
if (empty($user)) {
throw new UsernameNotFoundException('The user is not authenticated on twitter');
}
return $user;
}
public function refreshUser(UserInterface $user)
{
if (!$this->supportsClass(get_class($user)) || !$user->getTwitterID()) {
throw new UnsupportedUserException(sprintf('Instances of "%s" are not supported.', get_class($user)));
}
return $this->loadUserByUsername($user->getTwitterID());
}
}
@lukeman83 typehint the UserManagerInterface in your constructor instead of the implementation (which is not the one used by your FOSUserBundle setup)
Like this?
public function __construct(TwitterOAuth $twitter_oauth, Validator $validator, Session $session)
{
$this->twitter_oauth = $twitter_oauth;
$this->userManager = new UserManager();
$this->validator = $validator;
$this->session = $session;
}
I'm talking about changing the typehint, not about creating a new manager magically (which don't work anyway as it has some required dependencies):
use \TwitterOAuth;
-use FOS\UserBundle\Entity\UserManager;
+use FOS\UserBundle\Model\UserManagerInterface;
use Symfony\Component\Validator\Validator;
class TwitterUserProvider implements UserProviderInterface
{
/**
* @var \Twitter
*/
protected $twitter_oauth;
protected $userManager;
protected $validator;
protected $session;
- public function __construct(TwitterOAuth $twitter_oauth, UserManager $userManager,Validator $validator, Session $session)
+ public function __construct(TwitterOAuth $twitter_oauth, UserManagerInterface $userManager,Validator $validator, Session $session)
{
On a side node, you should also use the ValidatorInterface for the typehint instead of the implementation.
I did same things for Validator and Session. At the moment my TwitterProvider.php is this:
namespace project\UserBundle\Security\User\Provider;
use Symfony\Component\Security\Core\Exception\UsernameNotFoundException;
use Symfony\Component\Security\Core\Exception\UnsupportedUserException;
use Symfony\Component\Security\Core\User\UserProviderInterface;
use Symfony\Component\Security\Core\User\UserInterface;
use Symfony\Component\HttpFoundation\Session\SessionInterface;
use \TwitterOAuth;
use FOS\UserBundle\Model\UserManagerInterface;
use Symfony\Component\Validator\ValidatorInterface;
class TwitterProvider implements UserProviderInterface
{
/**
* @var \Twitter
*/
protected $twitter_oauth;
protected $userManager;
protected $validator;
protected $session;
public function __construct(TwitterOAuth $twitter_oauth, UserManagerInterface $userManager, ValidatorInterface $validator, SessionInterface $session)
{
$this->twitter_oauth = $twitter_oauth;
$this->userManager = $userManager;
$this->validator = $validator;
$this->session = $session;
}
public function supportsClass($class)
{
return $this->userManager->supportsClass($class);
}
public function findUserByTwitterId($twitterID)
{
return $this->userManager->findUserBy(array('twitterID' => $twitterID));
}
public function loadUserByUsername($username)
{
$user = $this->findUserByTwitterId($username);
$this->twitter_oauth->setOAuthToken( $this->session->get('access_token') , $this->session->get('access_token_secret'));
try {
$info = $this->twitter_oauth->get('account/verify_credentials');
} catch (Exception $e) {
$info = null;
}
if (!empty($info)) {
if (empty($user)) {
$user = $this->userManager->createUser();
$user->setEnabled(true);
$user->setPassword('');
$user->setAlgorithm('');
}
$username = $info->screen_name;
$user->setTwitterID($info->id);
$user->setTwitterUsername($username);
$user->setEmail('');
$user->setFirstname($info->name);
$this->userManager->updateUser($user);
}
if (empty($user)) {
throw new UsernameNotFoundException('The user is not authenticated on twitter');
}
return $user;
}
public function refreshUser(UserInterface $user)
{
if (!$this->supportsClass(get_class($user)) || !$user->getTwitterID()) {
throw new UnsupportedUserException(sprintf('Instances of "%s" are not supported.', get_class($user)));
}
return $this->loadUserByUsername($user->getTwitterID());
}
}
This is the error I get:
User provider "FOS\TwitterBundle\Security\Authentication\Provider\TwitterProvider" must implement "Symfony\Component\Security\Core\User\UserProviderInterface".
what is your security config ? FOS\TwitterBundle\Security\Authentication\Provider\TwitterProvider
is not a userr provider. It is an authentication provider
imports:
- { resource: facebookParameters.ini }
jms_security_extra:
secure_all_services: false
expressions: true
security:
#factories:
# - "%kernel.root_dir%/../vendor/bundles/FOS/FacebookBundle/Resources/config/security_factories.xml"
providers:
my_fos_facebook_provider:
id: my.facebook.user
my_fos_twitter_provider:
id: my.twitter.user
fos_userbundle:
id: fos_user.user_manager
fos_twitter:
id: fos_twitter.auth
encoders:
FOS\UserBundle\Model\UserInterface: sha512
Symfony\Component\Security\Core\User\User: plaintext
firewalls:
main:
pattern: ^/
form_login:
provider: fos_userbundle
csrf_provider: form.csrf_provider
fos_facebook:
app_url: %facebookAppUrl%
server_url: %facebookServerUrl%
login_path: /login
check_path: /login_fb_check
default_target_path: /
provider: my_fos_facebook_provider
logout:
handlers: ["fos_facebook.logout_handler"]
anonymous: true
secured:
pattern: /secured/.*
fos_twitter: true
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
public:
pattern: /.*
anonymous: true
fos_twitter: true
logout: true
access_control:
- { path: ^/login$, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/register, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: ^/resetting, role: IS_AUTHENTICATED_ANONYMOUSLY }
- { path: /.*, role: [IS_AUTHENTICATED_ANONYMOUSLY] }
- { path: ^/admin/, role: ROLE_ADMIN }
role_hierarchy:
ROLE_ADMIN: ROLE_USER
ROLE_SUPER_ADMIN: [ROLE_USER, ROLE_ADMIN, ROLE_ALLOWED_TO_SWITCH]
The indentation of your YAML snippet is missing, making it wrong.
And this is not the full security config
I updated it.
fos_twitter.auth
is not a user provider. You should not configure a user provider using this id.
I'm sorry! I didn't understand what is the correct way to solve this problem. Which Id must I use for user provider? Thanks a lot!
Can you help me please!
@stof "fos_twitter.auth is not a user provider. You should not configure a user provider using this id." => so there is a mistake in the documentation (https://github.com/FriendsOfSymfony/FOSTwitterBundle#installation, see point 4)
hmm, indeed
I have the same problem, so what is the right version of installing FOSTwitterBundle?
Here is the version I use :+1:
security: #... providers: #... acme_twitter_provider: id: acme.twitter.user # a custom provider
firewalls: main: #... fos_twitter: login_path: /twitter/login check_path: twitter_login_check default_target_path: /welcome-twitter # a custom route provider: acme_twitter_provider # my custom provider (see above)
Hope it will help
Hi, I integrated FOSUserBundle, FOSFacebookBundle, FOSMessageBundle and it was ok! Now I'm integrating FOSTwitterBundle together without twitter anywhere and I have this problem:
ErrorException: Catchable Fatal Error: Argument 2 passed to project\UserBundle\Security\User\Provider\TwitterProvider::__construct() must be an instance of FOS\UserBundle\Entity\UserManager, instance of FOS\UserBundle\Doctrine\UserManager given, called in /Applications/MAMP/htdocs/project/app/cache/dev/appDevDebugProjectContainer.php on line 2085 and defined in /Applications/MAMP/htdocs/project/src/project/UserBundle/Security/User/Provider/TwitterProvider.php line 25
What's the solution?
Another question... I read FOStwitterBundle documentation and it says:
//app/security.yml public: pattern: /.* anonymous: true fos_twitter: true logout: true
and//app/security.yml public: pattern: / fos_twitter: login_path: /twitter/login check_path: /twitter/login_check default_target_path: / provider: my_fos_twitter_provider anonymous: ~
Which is the right way?
Many thanks!!