Vlastní user s daty z FB API
- Orlando
- Člen | 10
Zdravím,
už nějaký čas se učím Nette, ale pořád jsem nepochopil, jak vytvořit vlastní User třídu. Respektive, přišel, ale:
- Vlastní user: řekl bych, že to nedělám správně (viz. níže na příkladu)
- potřebuji, aby ten user byl vytvořen/přihlášen z autentifikace z Facebook API (nevím jak)
- nevím, jak správně ošetřit presenter na onu „zabezpečenou sekci“
Detailněji k bodu 1) Vlastní user:
User.php
namespace App\Services\User;
use \Nette\Security\IIdentity;
class User extends \Nette\Security\User{
public function login($id = NULL, $user_info = array()){ // id = FB ID, user_info = array se ziskanym profilem (jmeno, mail, profilovka atd...)
$this->logout(TRUE);
if (!$id instanceof IIdentity) {
$id = $this->getAuthenticator()->authenticate(array("id"=>$id, "info"=>$user_info));
}
if ($id->getId()>0){
$this->storage->setIdentity($id);
$this->storage->setAuthenticated(TRUE);
$this->onLoggedIn($this);
}
}
public function isLoggedIn(){
return $this->getId() > 0;
}
}
UserAuth.php
namespace App\Services\User;
use Nette\Security\AuthenticationException;
class UserAuth implements \Nette\Security\IAuthenticator{
function authenticate(array $credentials) // credentials = array s udaji, [id] = FB ID
{
if (isset($credentials["id"]) && intval($credentials["id"])>0) return new UserIdentity($credentials["id"], $credentials["info"]);
else throw new AuthenticationException("UserAuth: No Facebook user id");
}
}
UserIdentity.php
namespace App\Services\User;
class UserIdentity implements \Nette\Security\IIdentity{
private $fb_id;
private $info = array();
public function __construct($fb_id = 0, $fb_user_info = array()){ // opet fb_id= FB ID, fb_user_info = info z FB profilu
$this->fb_id = bigintval($fb_id);
$this->info = $fb_user_info;
}
function getInfo(){
return $this->info; // vrati info o uzivateli
}
function getId()
{
return $this->fb_id; // vrati FB ID
}
function getRoles()
{
return array();
}
}
To by mi možná fungovalo, ale pak nastává ten „miš-maš“, kde musím v presenteru dělat „psí kusy“ a řešit přihlašování tam…
Pročetl jsem ofiko dokumentaci, vztahující se k tomuto problému, spoustu fór (většina je stejně zastaralá) a nejsem z toho moc chytrý.
Chtěl bych to spíše řešit „vlastnímy slovy“, navodu je hodně, ale tento problém je fakt malo popsanej…
Velké díky všem, kteří mi pomůžou s těmito „problémy“ :)
// Nette 2.2
// PHP 5.4
- Pavel Kravčík
- Člen | 1196
A zkoušel si postupně přepisovat UserManager a ACL? To je pro začátek nejjednodušší.
- Pavel Kravčík
- Člen | 1196
Psí kusy nemusíš dělat. Stačí něco podobného a pak to dá jen do startup() v BasePresenter.
protected function initLogin()
{
$user = $this->getUser();
/* Nepřihlášený uživatel */
if(!$user->isLoggedIn())
{
/* redirect přihlášení */
}
else
{
/* další funkčnost, změna hesla, odhlášení po hodině neaktivity, stavy */
}
}
- Pavel Kravčík
- Člen | 1196
@Orlando: Už jsem jak ostatní Nettaři. :( Beru tyhle věci jako samozřejmost, přitom ještě před 2 měsíci jsem taky neměl šajnu, že něco takového existuje.
Tak to vyzkoušej, nevypadá to špatně. Já se nedostanu na jejich stránky, abych viděl API. Máme blokovaný FB.
- Orlando
- Člen | 10
Takže, chápu-li dobře, presenter by pak vypadal asi takhle?
namespace App\Presenters\BackModule;
use App\Presenters\MainBasePresenter as BP;
class BasePresenter extends BP
{
function checkRequirements(){
$this->initLogin();
}
protected function initLogin()
{
$user = $this->getUser();
if(!$user->isLoggedIn())
{
$this->redirect("Front:Login:login");
}
}
.
.
.
.
.
}
- Etch
- Člen | 403
namespace App\Presenters\BackModule;
use App\Presenters\MainBasePresenter as BP;
class BasePresenter extends BP
{
function checkRequirements($element){
$this->initLogin();
}
protected function initLogin()
{
$user = $this->getUser();
if(!$user->isLoggedIn())
{
$this->redirect("Front:Login:login");
}
}
.
}
ale to záleží na tom co potřebuješ klidně může vypadat třeba i takhle:
namespace App\Presenters\BackModule;
use App\Presenters\MainBasePresenter as BP;
use Nette\Application;
class BasePresenter extends BP
{
function checkRequirements($element){
try{
parent::checkRequirements($element);
}catch(Application\ForbiddenRequestException $exception){
$this->redirect("Front:Login:login");
}
}
.
}
a následně, když chceš aby k nějakému presenteru nebo klidně jen některým akcím presenteru měly přístup jen přihlášení uživatelé tak mu přidáš anotaci
/**
* @User loggedIn
*/
nejjednodušší je se kouknout na API na její výchozí implementaci.
Editoval Etch (14. 1. 2015 17:48)
- Orlando
- Člen | 10
Tak to je dokonalý !!! Takové věci jsem v dokumentaci třeba nenašel :)
Takže ve finále tu metodu, cos psal výše, když dám do úplně hlavního presenteru od kterého se dědí Base presentery daných modulů a pak následně jednotlivé presentery,tak stačí u definice presenteru přidat anotaci a vše je vyřešené?
// podotýkám, že celá aplikace má být založena pouze na loginu a práv z FB
- Orlando
- Člen | 10
Nicméně, zkouším to různými způsoby, ale toto:
namespace App\Presenters\BackModule;
use App\Presenters\MainBasePresenter as BP;
/**
* @User loggedIn
*/
class BasePresenter extends BP {
}
A rodič (Uplne hlavni presenter):
namespace App\Presenters;
use Nette,
App\Model;
/**
* Base presenter for all application presenters.
*/
abstract class MainBasePresenter extends Nette\Application\UI\Presenter
{
/**
* @var \App\Services\User\User
* @inject
*/
var $user;
/**
* @var \Nette\Database\Context
*/
var $db;
public function __construct(\Nette\Database\Context $context){
parent::__construct();
$this->db = $context;
}
function checkRequirements($element){
try{
parent::checkRequirements($element);
}catch(\Nette\Application\ForbiddenRequestException $exception){
$this->redirect(":Front:Login:login");
}
}
}
… nefunguje popsaným způsobem
- Orlando
- Člen | 10
Tak ať se s tím peru jak chci, pořád asi dělám někde chybu.
Uživatele a zjištění, zda je přihlášen dělám v metodě startup ve
společným presenteru pro všechny moduly.
V modulu Admin (tedy, zabezpečený) opět ve společném presenteru,
tentokrát pouze pro daný modul, děděný ze společného pro všechny moduly,
v metodě startup zavolám parent::startup(); a hned na to kontroluji, zda je
uzivatel přihlášen.
Po přihlášení z FB API se sice do adminu dostanu, ale po jakémkoliv refresh/načtení jiné stránky už ne… Se sessions nikde nemanipuluju, jsou autostart. FB SDK přistupuje k SESSION napřímo, nebude problém v tom?
Dumpuju tu snad všechno za každé situace, ale nemůžu dohledat problém…
- Pavel Kravčík
- Člen | 1196
A jak by mělo fungovat FB API? Samo si držet session? Nebo jen vrací přihlášen/nepřihlášen a tu hodnotu si máš držet ty?
Můžeš se podívat, jestli dojde k vytvoření souboru „.sessionFBSKDK“ přímo na locale, ne? Pak už se posuneš o krok dál, jestli je to Nette/FB API/práva zápisu/správná složka pro zápis session.