Jednoduché přihlašování přes Google
- Tečník
- Člen | 18
Hledám nějaké jednoduché řešení, které bude schopen rozchodit i začátečník. Ideálně i s příkladem.
Našel jsem https://github.com/Kdyby/Google https://github.com/…social-login a https://github.com/martenb/google.
Šel jsem podle dokumentace a postupně řešil chyby, které vyskakovaly, ale nepodařilo se mi žádný z nich rozchodit.
- jiri.pudil
- Nette Blogger | 1029
Používám napřímo league/oauth2-google, zhruba takto:
parameters:
google:
clientId: # fill in config.local.neon
clientSecret: # fill in config.local.neon
services:
oauth2.google.factory:
create: MyApp\Google\Login\GoogleProviderFactory(%google.clientId%, %google.clientSecret%)
autowired: false
oauth2.google:
type: League\OAuth2\Client\Provider\Google
create: @oauth2.google.factory::create()
namespace MyApp\Google\Login;
use League\OAuth2\Client\Provider\Google;
use Nette\Application\LinkGenerator;
final class GoogleProviderFactory
{
/** @var string */
private $clientId;
/** @var string */
private $clientSecret;
/** @var LinkGenerator */
private $linkGenerator;
public function __construct(
string $clientId,
string $clientSecret,
LinkGenerator $linkGenerator
)
{
$this->clientId = $clientId;
$this->clientSecret = $clientSecret;
$this->linkGenerator = $linkGenerator;
}
public function create(): Google
{
return new Google([
'clientId' => $this->clientId,
'clientSecret' => $this->clientSecret,
'redirectUri' => $this->linkGenerator->link('Front:Login:google'),
]);
}
}
namespace MyApp\FrontModule;
use League\OAuth2\Client\Provider\Google;
use League\OAuth2\Client\Provider\GoogleUser;
use Nette\Application\UI\Presenter;
class LoginPresenter extends Presenter
{
/** @var Google */
private $google;
public function handleGoogleLogin(): void
{
$authorizationUrl = $this->google->getAuthorizationUrl([
'redirect_uri' => $this->link('//google'),
]);
$this->getSession(Google::class)->state = $this->google->getState();
$this->redirectUrl($authorizationUrl);
}
public function actionGoogle(): void
{
$error = $this->getParameter('error');
if ($error !== null) {
$this->flashMessage('... google login error ...', 'error');
$this->redirect('default');
}
$state = $this->getParameter('state');
$stateInSession = $this->getSession(Google::class)->state;
if ($state === null || $stateInSession === null || ! \hash_equals($stateInSession, $state)) {
$this->flashMessage('... invalid CSRF token ...', 'error');
$this->redirect('default');
}
// reset CSRF protection, it has done its job
unset($this->getSession(Google::class)->state);
$accessToken = $this->google->getAccessToken('authorization_code', [
'code' => $this->getParameter('code'),
'redirect_uri' => $this->link('//google'),
]);
try {
/** @var GoogleUser $googleUser */
$googleUser = $this->google->getResourceOwner($accessToken);
} catch (\Throwable $e) {
$this->flashMessage('... cannot retrieve user profile ...', 'error');
$this->redirect('default');
}
$googleId = $googleUser->getId();
if ($user = $this->userRepository->findByGoogleId($googleId)) {
// found existing user by googleId, login and redirect
$this->user->login($user);
$this->redirect('Homepage:');
}
$googleEmail = $googleUser->getEmail();
if ($user = $this->userRepository->findByEmail($googleEmail)) {
// found existing user with the same email, error and force them to login using password
$this->flashMessage('... somebody already signed up with given email ...', 'error');
$this->redirect('default');
}
// new user, register them, login and redirect
$user = $this->userRepository->registerFromGoogle($googleUser);
$this->user->login($user);
$this->redirect('Homepage:');
}
}
Je potřeba dávat si pozor hlavně na to, abys měl u své aplikace
v Google Developer Console nastavené všechny možné správné
redirect_uri
s, Google je ohledně nich hodně striktní.
- jiri.pudil
- Nette Blogger | 1029
@MajklNajt heslo tady neřeším a IAuthenticator
vůbec
neimplementuji; do Nette\Security\User::login()
lze předat rovnou
identitu (kterou mi implementuje entita uživatele) a v takovém případě už
se
authenticator nevolá.
- Tečník
- Člen | 18
Děkuji za odpověď a velice se omlouvám, ale jsem skutečně začátečník a přiloženým souborům rozumím ještě méně než těm, které jsou v dokumentaci řešení, která jsem zmínil.
Budu rád, když mi poradíte blíže, co s nimi, nebo ještě lépe, kdyby někdo měl funkční příklad, který bych si u sebe rozbalil a mohl se podívat, co kde je.
Podařilo se mi pomocí composeru nainstalovat league/oauth2-google a mám i potřebné hodnoty clientId a clientSecret.
Pochopil jsem, co mám přidat do config.neon, bohužel ale nevím, kam nahrát druhý soubor s továrnou a pod jakým názvem a jak pak upravit cestu k němu v nastavení služby.
Chápu, že druhý soubor je presenter, který se bude používat, ale bohužel nevím, jak jej pak použít v šabloně. A nevím, co přesně dělá handleGoogleLogin().
- CZechBoY
- Člen | 3608
Soubory umísti tam kde odpovídá cesta namespace – tzn. Factory umísti
do App/Google/Login/GoogleProviderFactory.php
a presenter třeba do
App/Presenters
.
Vesměs je jedno kam ty soubory umístíš, RobotLoader si je najde pod složkou
App
kdekoliv.
Celý tohle bys měl v šabloně použít asi takto (v Login šabloně):
<a n:href="googleLogin!">Přihlásit přes Google</a>
- jiri.pudil
- Nette Blogger | 1029
Nechybí tam někde nějaká část, kde se ta proměnná $google inicializuje?
Omlouvám se, to jsem v rámci zjednodušení příkladu vynechal.
Nejsnáze úpravou atributu v presenteru takto:
/** @var Google @inject */
public $google;
a nejčistěji vyžádáním v konstruktoru presenteru:
/** @var Google */
private $google;
public function __construct(Google $google)
{
$this->google = $google;
}
V obou případech se o dosazení správné instance postará DI kontejner.
Editoval jiri.pudil (28. 2. 2019 14:52)
- Tečník
- Člen | 18
Pokouším se použít přihlašování ze sandboxu a umožnit uživateli
registrovat/přihlásit se přes heslo nebo přes google.
Ale bohužel moc nevím, kudy na to.
Začal jsem tím, že jsem tabulku rozšířil o googleId a do třídy UserManager ze sandboxu přidal metodu registerFromGoogle() a ještě to bude chtít findByGoogleId() a findByEmail(). To by neměl být problém.
Otázka ale je, jak napsat dva různé autentikátory.
- Upravit metodu authenticate ze stávajícího UserManager.php tak, aby uměla reagovat na heslo i gogleId?
- Nebo všechno rozdělit na dvě části (UserManager a GoogleUserManager) a pouštět přihlášení podobně, jako je to popsáno v dokumentaci?
Nebo na to jdu úplně špatně?
- unjustolaf
- Člen | 29
@jiripudil
Ahoj, parádní tutoriál ale mám jednu chybu se kterou si nevím rady, při zaregistrování komponenty v configu mi vyskakuje error „Service ‚oauth2.google‘: Unknown or deprecated key ‚type‘ in definition of service.“ zkoušel jsem už všechno a nedokázal jsem na to přijít, nějaké nápady co by mohlo být špatně?
Předem děkuji.
Jakub
- MajklNajt
- Člen | 497
@Tečník o tomto bol práve môj príspevok – na prihlasovanie
cez google nepotrebuješ vôbec authenticator, túto funkciu za teba plní
google – z managera si vrátiš už rovno entitu (ktorá implementuje
IIdentity
), a metóde Nette\Security\User::login()
dáš už len túto entitou, kedy sa authenticator obíde
- jiri.pudil
- Nette Blogger | 1029
@unjustolaf @CZechBoY class
je myslím deprecated,
type
ho nahrazuje, ale až od nette/di ^2.4.10
@Tečník v tom mém řešení právě žádný speciální
autentikátor pro Google není potřeba. Souvisí to s tím, co jsme tu
řešili s @MajklNajt – dole se volá
$this->user->login($user)
, tj. do login metody předávám
rovnou nějakou svou vlastní implementaci IIdentity
. V tom
případě Nette danou identitu rovnou přihlásí a autentikátor už se
nevolá.
- cvit84
- Člen | 43
Zdravím.
Používám league/oauth2-google, a píše mi to: „1 passed to App\Models\Googleaccount\GoogleButton::__construct() must be of the type string, null given, called in C:\xampp\htdocs\nalezce\temp\cache\nette.configurator\Container_406aa2b1f1.php on line 615 search►“
nevím co je špatně. Myslel jsem si že stačí když budu přihlašeny na google a po kliknutí na handle to se údaje uloží. Ale píše mi to že je parametr nula. A já nevím jak tam mám dostat ty vstupní data. Může mi prosím někdo pomoct. Děkuji Vítek
- cvit84
- Člen | 43
Zdravím. nedaří se mi uložit data z google učtu. Hlasí mi to:
Argument 1 passed to Nette\Database\Table\Selection::insert() must be iterable, object given, called in /var/www/site-local/nalezce.cz/app/Models/Db/AbstractTable.php on line 54
…/site-local/nalezce.cz/app/Models/Db/AbstractTable.php:54
44: public function save($data, $id = null) {
45: if (is_null($id)) {
46: $this->findAll()->insert($data);
47: } else {
48: $this->findAll()->where($this::ID_COLUMN_NAME,
$id)->update($data);
49: }
50: }
51:
52: public function saveg($data) {
53:
54: $this->findAll()->insert($data);
55:
56: }
57:
58: public function saveAll($data) {
$data
League\OAuth2\Client\Provider\GoogleUser
response: array
‚sub‘ ⇒ ‚116217675099718320994‘
‚name‘ ⇒ ‚Vít Cigánek‘
‚given_name‘ ⇒ ‚Vít‘
‚family_name‘ ⇒ ‚Cigánek‘
‚picture‘ ⇒
‚https://lh3.googleusercontent.com/a/AATXAJycOoEzCl9l5RR9KCkpUxtXeW48yQiV6keC4G8p=s96-c‘
‚email‘ ⇒ ‚ciganekv84@gmail.com'
'email_verified‘ ⇒ true
‚locale‘ ⇒ ‚cs‘
…/www/site-local/nalezce.cz/app/Models/Db/DbUserg.php:27
…/site-local/nalezce.cz/app/Presenters/GooglePresenter.php:74
inner-code
App\Presenters\GooglePresenter::actionGoogle ()
…/nette/application/src/Application/UI/Component.php:120
…/nette/application/src/Application/UI/Presenter.php:216
…/vendor/nette/application/src/Application/Application.php:163
…/vendor/nette/application/src/Application/Application.php:90
/var/www/site-local/nalezce.cz/www/index.php:10
Nevím jak uložit pole. Podle mě to chce object. Ale v parametru mam pole. Prosím o radu.
- petr.pavel
- Člen | 535
Jak praví chybová hláška, předáváš objekt, akceptuje to pole.
Když se podíváš do definice GoogleUser
, najdeš metodu
toArray().
https://github.com/…ogleUser.php#L5