我使用了这个教程:https://github.com/knpuniversity/oauth2-client-bundle。
我使用的版本是Symfony 6.1.12和PHP 8.1.0。
目前,我使用Google登录,但没有使用Facebook登录。我错过了什么?
感谢我的FacebookController.php中的var_dump($user);
,我可以看到我的Facebook数据出现。但我没有连接到Facebook。
因为它与谷歌工作,我也从GoogleController.php和GoogleAuthenticator.php共享代码。
感谢你的帮助.
我在config/packages/knpu_oauth2_client.yaml中的代码:
knpu_oauth2_client:
clients:
facebook:
type: facebook
client_id: '%env(OAUTH_FACEBOOK_ID)%'
client_secret: '%env(OAUTH_FACEBOOK_SECRET)%'
redirect_route: connect_facebook_check
redirect_params: {}
graph_api_version: v2.12
在安全方面。
security:
password_hashers:
Symfony\Component\Security\Core\User\PasswordAuthenticatedUserInterface: 'auto'
providers:
app_user_provider:
entity:
class: App\Entity\User
property: email
oauth:
id: knpu.oauth2.user_provider
enable_authenticator_manager: true
firewalls:
dev:
pattern: ^/(_(profiler|wdt)|css|images|js)/
security: false
main:
lazy: true
provider: app_user_provider
form_login:
login_path: login
check_path: login
logout:
path: logout
target: home
entry_point: App\Security\AppCustomAuthenticator
custom_authenticators:
- App\Security\AppCustomAuthenticator
- App\Security\FacebookAuthenticator
access_control:
- { path: ^/admin, roles: ROLE_ADMIN }
- { path: ^/connect, roles: PUBLIC_ACCESS }
我在.env中添加了变量:
OAUTH_FACEBOOK_ID=fb_id
OAUTH_FACEBOOK_SECRET=fb_secret
我的FacebookController:
<?php
namespace App\Controller\Front;
use KnpU\OAuth2ClientBundle\Client\ClientRegistry;
use League\OAuth2\Client\Provider\Exception\IdentityProviderException;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Annotation\Route;
class FacebookController extends AbstractController
{
#[Route('/connect/facebook', name: 'connect_facebook')]
public function connectAction(ClientRegistry $clientRegistry)
{
return $clientRegistry
->getClient('facebook')
->redirect([
'public_profile', 'email'
], []);
}
#[Route('/connect/facebook/check', name: 'connect_facebook_check')]
public function connectCheckAction(Request $request, ClientRegistry $clientRegistry)
{
/** @var \KnpU\OAuth2ClientBundle\Client\Provider\FacebookClient $client */
$client = $clientRegistry->getClient('facebook');
try {
/** @var \League\OAuth2\Client\Provider\FacebookUser $user */
$user = $client->fetchUser();
var_dump($user); die;
} catch (IdentityProviderException $e) {
var_dump($e->getMessage()); die;
}
}
}
我的GoogleController:
<?php
namespace App\Controller\Front;
use KnpU\OAuth2ClientBundle\Client\ClientRegistry;
use Symfony\Bundle\FrameworkBundle\Controller\AbstractController;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\Routing\Annotation\Route;
class GoogleController extends AbstractController
{
#[Route('/connect/google', name: 'connect_google')]
public function connectAction(ClientRegistry $clientRegistry)
{
//Redirect to google
return $clientRegistry->getClient('google')->redirect([], []);
}
/**
* After going to Google, you're redirected back here
* because this is the "redirect_route" you configured
* in config/packages/knpu_oauth2_client.yaml
*/
#[Route('/connect/google/check', name: 'connect_google_check')]
public function connectCheckAction(Request $request)
{
return $this->redirectToRoute('home');
// ** if you want to *authenticate* the user, then
// leave this method blank and create a Guard authenticator
}
}
我的FacebookAuthenticator.php:
<?php
namespace App\Security;
use App\Entity\User;
use Doctrine\ORM\EntityManagerInterface;
use KnpU\OAuth2ClientBundle\Client\ClientRegistry;
use KnpU\OAuth2ClientBundle\Security\Authenticator\OAuth2Authenticator;
use League\OAuth2\Client\Provider\FacebookUser;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\RouterInterface;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Symfony\Component\Security\Http\Authenticator\Passport\Badge\UserBadge;
use Symfony\Component\Security\Http\Authenticator\Passport\Passport;
use Symfony\Component\Security\Http\Authenticator\Passport\SelfValidatingPassport;
use Symfony\Component\Security\Http\EntryPoint\AuthenticationEntryPointInterface;
class FacebookAuthenticator extends OAuth2Authenticator implements AuthenticationEntrypointInterface
{
private $clientRegistry;
private $entityManager;
private $router;
public function __construct(ClientRegistry $clientRegistry, EntityManagerInterface $entityManager, RouterInterface $router)
{
$this->clientRegistry = $clientRegistry;
$this->entityManager = $entityManager;
$this->router = $router;
}
public function supports(Request $request): ?bool
{
// continue ONLY if the current ROUTE matches the check ROUTE
return $request->attributes->get('_route') === 'connect_facebook_check';
}
public function authenticate(Request $request): Passport
{
$client = $this->clientRegistry->getClient('facebook');
$accessToken = $this->fetchAccessToken($client);
return new SelfValidatingPassport(
new UserBadge($accessToken->getToken(), function() use ($accessToken, $client) {
/** @var FacebookUser $facebookUser */
$facebookUser = $client->fetchUserFromToken($accessToken);
$email = $facebookUser->getEmail();
// 1) have they logged in with Facebook before? Easy!
$existingUser = $this->entityManager->getRepository(User::class)->findOneBy(['facebookId' => $facebookUser->getId()]);
if ($existingUser) {
return $existingUser;
}
// 2) do we have a matching user by email?
$user = $this->entityManager->getRepository(User::class)->findOneBy(['email' => $email]);
// 3) Maybe you just want to "register" them by creating
// a User object
$user->setFacebookId($facebookUser->getId());
$this->entityManager->persist($user);
$this->entityManager->flush();
return $user;
})
);
}
public function onAuthenticationSuccess(Request $request, TokenInterface $token, string $firewallName): ?Response
{
$targetUrl = $this->router->generate('home');
return new RedirectResponse($targetUrl);
}
public function onAuthenticationFailure(Request $request, AuthenticationException $exception): ?Response
{
$message = strtr($exception->getMessageKey(), $exception->getMessageData());
return new Response($message, Response::HTTP_FORBIDDEN);
}
/**
* Called when authentication is needed, but it's not sent.
* This redirects to the 'login'.
*/
public function start(Request $request, AuthenticationException $authException = null): Response
{
return new RedirectResponse(
'/connect/', // might be the site, where users choose their oauth provider
Response::HTTP_TEMPORARY_REDIRECT
);
}
}
我的GoogleAuthenticator.php:
<?php
namespace App\Security;
use App\Entity\User;
use League\OAuth2\Client\Provider\GoogleUser;
use Doctrine\ORM\EntityManagerInterface;
use KnpU\OAuth2ClientBundle\Client\ClientRegistry;
use KnpU\OAuth2ClientBundle\Security\Authenticator\OAuth2Authenticator;
use Symfony\Component\HttpFoundation\RedirectResponse;
use Symfony\Component\HttpFoundation\Request;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\Routing\RouterInterface;
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
use Symfony\Component\Security\Core\Exception\AuthenticationException;
use Symfony\Component\Security\Http\Authenticator\Passport\Badge\UserBadge;
use Symfony\Component\Security\Http\Authenticator\Passport\Passport;
use Symfony\Component\Security\Http\Authenticator\Passport\SelfValidatingPassport;
class GoogleAuthenticator extends OAuth2Authenticator
{
private ClientRegistry $clientRegistry;
private EntityManagerInterface $entityManager;
private RouterInterface $router;
public function __construct(ClientRegistry $clientRegistry, EntityManagerInterface $entityManager, RouterInterface $router)
{
$this->clientRegistry = $clientRegistry;
$this->entityManager = $entityManager;
$this->router = $router;
}
public function supports(Request $request): ?bool
{
// continue ONLY if the current ROUTE matches the check ROUTE
return $request->attributes->get('_route') === 'connect_google_check';
}
public function authenticate(Request $request): Passport
{
$client = $this->clientRegistry->getClient('google');
$accessToken = $this->fetchAccessToken($client);
return new SelfValidatingPassport(
new UserBadge($accessToken->getToken(), function () use ($accessToken, $client) {
/** @var GoogleUser $googleUser */
$googleUser = $client->fetchUserFromToken($accessToken);
$email = $googleUser->getEmail();
// have they logged in with Google before? Easy!
$existingUser = $this->entityManager->getRepository(User::class)->findOneBy(['email' => $email]);
//User doesnt exist, we create it !
if (!$existingUser) {
$existingUser = new User();
$existingUser->setEmail($email);
$existingUser->setGoogleId($googleUser->getId());
$existingUser->setHostedDomain($googleUser->getHostedDomain());
$this->entityManager->persist($existingUser);
}
$existingUser->setAvatar($googleUser->getAvatar());
$this->entityManager->flush();
return $existingUser;
})
);
}
public function onAuthenticationSuccess(Request $request, TokenInterface $token, string $firewallName): ?Response
{
return new RedirectResponse(
$this->router->generate('home')
);
// or, on success, let the request continue to be handled by the controller
//return null;
}
public function onAuthenticationFailure(Request $request, AuthenticationException $exception): ?Response
{
$message = strtr($exception->getMessageKey(), $exception->getMessageData());
return new Response($message, Response::HTTP_FORBIDDEN);
}
/**
* Called when authentication is needed, but it's not sent.
* This redirects to the 'login'.
*/
public function start(Request $request, AuthenticationException $authException = null): Response
{
return new RedirectResponse(
'/connect/',
Response::HTTP_TEMPORARY_REDIRECT
);
}
}
2条答案
按热度按时间gcuhipw91#
您的connectCheckAction不为空,如果您使用Symfony Authenticator并删除安全文件中的以下行,则应为空:
qhhrdooz2#
检查您的Facebook应用程序身份验证。您应该有appid,secret,domain和https重定向URL。尝试托管您的网站而不是localhost,并确保它是https。
https://developers.facebook.com/docs/development/create-an-app/app-dashboard/basic-settings/