2016-11-12 70 views
0

我试图在网站中实现Facebook连接。但是,当我通过连接过程时,我会返回到登录页面页面,因为身份验证会立即到期。 我也有一个独立的规则注册和登录本Symfony 3 FB登录 - OAuth登录流后,我回到登录页面,因为身份验证立即过期

控制器:

<?php 

namespace Vendor\GiftBundle\Controller; 

use Sensio\Bundle\FrameworkExtraBundle\Configuration\Route; 
use Symfony\Bundle\FrameworkBundle\Controller\Controller; 
use Symfony\Component\HttpFoundation\Request; 
use Symfony\Component\HttpFoundation\Response; 
use Symfony\Component\Routing\Generator\UrlGeneratorInterface; 

class FacebookConnectController extends Controller 
{ 
    /** 
    * @Route("/connect/facebook", name="connect_facebook") 
    */ 
    public function connectFacebookAction(Request $request) 
    { 

     // redirect to Facebook 
     $facebookOAuthProvider = $this->get('app.facebook_provider'); 
     $url = $facebookOAuthProvider->getAuthorizationUrl([ 
      // these are actually the default scopes 
      'scope' => ['public_profile', 'email'], 
      //'redirect_uri' => [$redir], 
     ]); 

     return $this->redirect($url); 
    } 

    /** 
    * @Route("/connect/facebook-check", name="connect_facebook_check") 
    */ 
    public function connectFacebookActionCheck() 
    { 
     // will not be reached! 
    } 
} 

Facebook的身份验证:

<?php 

namespace Vendor\GiftBundle\Security; 

use Symfony\Component\Security\Guard\AbstractGuardAuthenticator; 
use Symfony\Component\HttpFoundation\Request; 
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface; 
use Symfony\Component\Security\Core\Exception\AuthenticationException; 
use Symfony\Component\Security\Core\User\UserInterface; 
use Symfony\Component\Security\Core\User\UserProviderInterface; 
use Symfony\Component\DependencyInjection\ContainerInterface; 
use Vendor\GiftBundle\Entity\Logins; 
use Symfony\Component\HttpFoundation\RedirectResponse; 
use Symfony\Component\HttpFoundation\Response; 
use Symfony\Component\Security\Core\Security; 
use Symfony\Component\Security\Core\Authentication\Token\UsernamePasswordToken; 

class FacebookAuthenticator extends AbstractGuardAuthenticator 
{ 
    private $container; 

    public function __construct(ContainerInterface $container) 
    { 
     $this->container = $container; 
    } 

    public function getCredentials(Request $request) 
    { 
     if ($request->getPathInfo() != '/connect/facebook-check') { 
      // skip authentication unless we're on this URL! 
      return null; 
     } 
     if ($code = $request->query->get('code')) { 
      return $code; 
     } 
     // no code! Something went wrong. Quite probably the user denied our app access 
     // you could read the error, error_code, error_description, error_reason query params 
     // http://localhost:8000/connect/facebook-check?error=access_denied&error_code=200&error_description=Permissions+error&error_reason=user_denied&state=S2fKgHJSZSJM0Qs2fhKL6USZP50KSBHc#_=_ 

     throw CustomAuthenticationException::createWithSafeMessage(
      'There was an error getting access from Facebook. Please try again.' 
     ); 
    } 

    public function getUser($authorizationCode, UserProviderInterface $userProvider) 
    { 
     //$user = new Logins(); 
     $facebookProvider = $this->container->get('app.facebook_provider'); 
     try { 
      // the credentials are really the access token 
      $accessToken = $facebookProvider->getAccessToken(
       'authorization_code', 
       ['code' => $authorizationCode] 
      ); 
     } catch (IdentityProviderException $e) { 
      // probably the authorization code has been used already 
      $response = $e->getResponseBody(); 
      $errorCode = $response['error']['code']; 
      $message = $response['error']['message']; 
      throw CustomAuthenticationException::createWithSafeMessage(
       'There was an error logging you into Facebook - code '.$errorCode 
      ); 

     } 

     /** @var FacebookUser $facebookUser */ 
     $facebookUser = $facebookProvider->getResourceOwner($accessToken); 
     $email = $facebookUser->getEmail(); 

     //$em = $this->getDoctrine()->getManager(); 
     //$check = $em->getRepository('VendorGiftBundle:Logins')->findByEmail($email); 

     $em = $this->container->get('doctrine')->getManager(); 
     // 1) have they logged in with Facebook before? Easy! 
     $existingUser = $em->getRepository('VendorGiftBundle:Logins') 
      ->findOneBy(array('fbid' => $facebookUser->getId())); 
     if ($existingUser) { 
      return $existingUser; 
     } 
     // 2) do we have a matching user by email? 
     $user = $em->getRepository('VendorGiftBundle:Logins') 
        ->findOneBy(array('email' => $email)); 
     // 3) no user? Perhaps you just want to create one 
     //  or maybe you want to redirect to a registration (in that case, keep reading_ 
     if (!$user) { 
      $user = new Logins(); 
      $user->setEmail($email); 
      $user->setFirstname($facebookUser->getFirstName()); 
      $user->setLastname($facebookUser->getLastName()); 
      $user->setCity($facebookUser->getLocale()); 
      $user->setCreationtime(); 
      $user->setStatus(1); 
      // set an un-encoded password, which basically makes it *not* possible 
      // to login with any password 
      $user->setPassword('no password'); 
     } 
     // make sure the Facebook user is set 
     $user->setFbid($facebookUser->getId()); 
     $em->persist($user); 
     $em->flush(); 
     return $user; 
     /* 
     if(!$check){ 
      $hash = uniqid(); 
      //Encode the password (you could also do this via Doctrine listener) 
      $password = $this->get('security.password_encoder') 
       ->encodePassword($user, $hash); 
      $user->setEmail($email); 
      $user->setFirstname($facebookUser->getFirstName()); 
      $user->setLastname($facebookUser->getLastName()); 
      $user->setCity($facebookUser->getLocale()); 
      $user->setPassword($password); 
      $user->setCreationtime(); 
      $user->setStatus(1); 
      // 4) save the User! 
      $em = $this->getDoctrine()->getManager(); 
      $em->persist($user); 
      $em->flush(); 
      return $user; 
     } 
     return $user; 
     * 
     */ 
    } 

    public function checkCredentials($credentials, UserInterface $user) 
    { 
     return true; 
    } 

    public function onAuthenticationFailure(Request $request, AuthenticationException $exception) 
    { 
     // this would happen if something went wrong in the OAuth flow 
     $request->getSession()->set(Security::AUTHENTICATION_ERROR, $exception); 
     $url = $this->container->get('router') 
      ->generate('login_route'); 
     return new RedirectResponse($url); 
    } 

    public function onAuthenticationSuccess(Request $request, TokenInterface $token, $providerKey) 
    { 
     $key = '_security.main.target_path'; #where "main" is your firewall name 

     //check if the referrer session key has been set 
     if ($this->container->get('session')->has($key)) { 
      //set the url based on the link they were trying to access before being authenticated 
      $url = $this->container->get('session')->get($key); 

      //remove the session key 
      $this->container->get('session')->remove($key); 
     } 
     //if the referrer key was never set, redirect to a default route 
     else{ 
      $url = $this->container->get('router')->generate('home_page'); 

     } 

     return new RedirectResponse($url); 
     // todo - remove needing this crazy thing 
     /* 
     $targetPath = $request->getSession()->get('_security.'.$providerKey.'.target_path'); 

     if ($targetPath) { 
      $router = $this->container->get('router'); 
      $targetPath = $router->generate('home_page'); 
     } 
     return new RedirectResponse($targetPath); 
     * 
     */ 
    } 

    public function supportsRememberMe() 
    { 
     return true; 
    } 



    /** 
    * Called when an anonymous user tries to access an protected page. 
    * 
    * In our app, this is never actually called, because there is only *one* 
    * "entry_point" per firewall and in security.yml, we're using 
    * app.form_login_authenticator as the entry point (so it's start() method 
    * is the one that's called). 
    */ 
    public function start(Request $request, AuthenticationException $authException = null) 
    { 
     // not called in our app, but if it were, redirecting to the 
     // login page makes sense 
     $url = $this->container->get('router') 
      ->generate('home_page'); 
     return new RedirectResponse($url); 

    } 

    protected function getDefaultSuccessRedirectUrl() 
    { 
     return $this->container->get('router')->generate('home_page'); 
    } 

    protected function getLoginUrl() 
    { 
     return $this->container->get('router')->generate('login_route'); 
    } 

    public function getDoctrine() 
    { 
     return $this->container->get('doctrine'); 
    } 

    public function get($id) 
    { 
     return $this->container->get($id); 
    } 

} 

Security.yml:

security: 

    # http://symfony.com/doc/current/book/security.html#where-do-users-come-from-user-providers 

    encoders: 
     Vendor\GiftBundle\Entity\Logins: 
      algorithm: bcrypt 
      cost: 13 
     Symfony\Component\Security\Core\User\User: 
      algorithm: bcrypt 
      cost: 13 

    #make admin inherit user access 
    role_hierarchy: 
     ROLE_ADMIN:  ROLE_USER 
#  ROLE_SUPER_ADMIN: ROLE_ADMIN 

    #provider of user authetification name, in our case, email 
    providers: 
     doctrine1: 
      entity: 
       class: Vendor\GiftBundle\Entity\Logins 
       property: email 
#  in_memory: 
#   memory: ~ 


    firewalls: 
     # disables authentication for assets and the profiler, adapt it according to your needs 
     dev: 
      pattern: ^/(_(profiler|wdt)|css|images|js)/ 
      security: false 

     main: 
      #pattern: ^/.* 
      #security: false 
      anonymous: ~ 
      form_login: 
       login_path: /login 
       check_path: /login_check 
       csrf_token_generator: security.csrf.token_manager 
       username_parameter: _email 
      provider: doctrine1 

      logout: 
       path: /logout 
       target:/

      anonymous: ~ 
      guard: 
       authenticators: 
        - app.facebook_authenticator 
       #entry_point: app.form_login_authenticator 
      #anonymous: ~ 
      # activate different ways to authenticate 

      # http_basic: ~ 
      # http://symfony.com/doc/current/book/security.html#a-configuring-how-your-users-will-authenticate 

      # form_login: ~ 
      # http://symfony.com/doc/current/cookbook/security/form_login_setup.html 

    access_control: 
     - { path: ^/connect, role: IS_AUTHENTICATED_ANONYMOUSLY } 
     - { path: ^/login, role: IS_AUTHENTICATED_ANONYMOUSLY } 
     - { path: ^/register, role: IS_AUTHENTICATED_ANONYMOUSLY } 
     - { path: ^/reset, role: IS_AUTHENTICATED_ANONYMOUSLY } 
     - { path: ^/sec, role: ROLE_USER } 
     - { path: ^/admin, role: ROLE_ADMIN } 
+0

我试图一步一步地调试与探查器在后台发生了什么。在我得到代码并检查用户Guard的身份验证成功之后,并且在我将用户发送到home_page之后,例如,会立即遇到表示验证已过期的异常。任何想法为什么它立即过期? '由于AccountStatusException,安全令牌已被删除。 上下文:{“exception”:“Object(Symfony \\ Component \\ Security \\ Core \\ Exception \\ AuthenticationExpiredException)”}} –

回答

0

我令牌手动生成。

public function onAuthenticationSuccess(Request $request, TokenInterface $token, $providerKey) 
{ 
    $token = new UsernamePasswordToken($token->getUser(), null, $providerKey, $token->getUser()->getRoles()); 
    $this->tokenStorage->setToken($token); 
    $request->getSession()->set('_security_main', serialize($token)); 

    $url = $this->router->generate("homepage"); 

    return new RedirectResponse($url); 
} 

试试这个。不要忘记注入TokenStorage。