Vlastní user s daty z FB API

Upozornění: Tohle vlákno je hodně staré a informace nemusí být platné pro současné Nette.
Orlando
Člen | 10
+
0
-

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:

  1. Vlastní user: řekl bych, že to nedělám správně (viz. níže na příkladu)
  2. potřebuji, aby ten user byl vytvořen/přihlášen z autentifikace z Facebook API (nevím jak)
  3. 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
+
0
-

A zkoušel si postupně přepisovat UserManager a ACL? To je pro začátek nejjednodušší.

Orlando
Člen | 10
+
0
-

Zkoušel, ve své podstatě z nich vycházím

Pavel Kravčík
Člen | 1196
+
0
-

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 */
	}
}
Orlando
Člen | 10
+
0
-

Děkuji! Třeba neznalost existence metody startup() mě způsobovala část oněch „psích kusů“. Právě jsem to testoval a zkoušel a šlape to, jako hodinky :)

Ten návrh celého obalu uživatele mám správně? Potřebuji to právě skloubit s propojením na FB API.

Pavel Kravčík
Člen | 1196
+
0
-

@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
+
0
-

S prací s FB API (SDK) problém nemám, spíš mám problém to skloubení dohromady

Etch
Člen | 403
+
0
-

K ověřování oprávnění se více hodí metoda checkRequirements(), která je volána ještě před startupem.

Orlando
Člen | 10
+
0
-

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
+
0
-
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
+
0
-

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
+
0
-

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

Etch
Člen | 403
+
0
-

Defaultní implementace dané metody nepodporuje „dědičnost“ a je nutné jí buď přepsat a nebo definovat přístupové pravidla na úrovni jednotlivejch presenterů.

Orlando
Člen | 10
+
0
-

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
+
0
-

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.

Orlando
Člen | 10
+
0
-

To session se vytvoří v pořádku, kontroloval jsem