Symfony 3 FB登录 - OAuth登录流后,我回到登录页面,因为身份验证立即过期
问题描述:
我试图在网站中实现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 }
答
我令牌手动生成。
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。
我试图一步一步地调试与探查器在后台发生了什么。在我得到代码并检查用户Guard的身份验证成功之后,并且在我将用户发送到home_page之后,例如,会立即遇到表示验证已过期的异常。任何想法为什么它立即过期? '由于AccountStatusException,安全令牌已被删除。 上下文:{“exception”:“Object(Symfony \\ Component \\ Security \\ Core \\ Exception \\ AuthenticationExpiredException)”}} –