Problém s autorizací a backlinkem

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

Ahoj, mírně jsem si poupravil Authorizator dle zdejšího fóra. Vše funguje tak jak očekávám, nicméně, pokud dojde k $this->restoreRequest($this->backlink); nastane problém. Nebo alespoň myslím, že je to tímhle.
Můj kód:

<?php

namespace Base\Model;

use Nette\Application\UI\Presenter;
use Nette\Security\IAuthorizator;

class Authorization implements IAuthorizator {
    private $presenter;
    private $authorization;

    public function __construct(Presenter $presenter, IAuthorizator $authorization) {
        $this->presenter = $presenter;
        $this->authorization = $authorization;
    }

    public function isAllowed($role, $name, $action) {
        $signal = $this->presenter->getSignal();
        if($this->isSignalFromPresenter($signal))
            $action = $signal[1] . '!';
        elseif($this->isSignalFromComponent($signal)) {
            $name = $name . ':' . $signal[0];
            $action = $signal[1] . '!';
        }
        return $this->authorization->isAllowed($role, $name, $action);
    }

    private function isSignalFromPresenter($signal) {
        return $signal && empty($signal[0]);
    }

    private function isSignalFromComponent($signal) {
        return $signal && $signal[0];
    }
}

<?php

namespace App\Base\Presenters;

use Base\Model\Authorization;

abstract class BasePresenter extends \Nette\Application\UI\Presenter {
    use \Nextras\Application\UI\SecuredLinksPresenterTrait;

    protected function checkAcl() {
        $authorization = new Authorization($this, $this->user->getAuthorizator());
        $this->user->setAuthorizator($authorization);
        if(!$this->user->isAllowed($this->getName(), $this->getAction())) {
            $this->flashMessage('Přístup odepřen. Prosím, přihlaste se');
            $this->redirect('Prihlaseni:', ['backlink' => $this->storeRequest()]);
            $this->redirect('Default:');
        }
    }

    protected function startup() {
        parent::startup();
        $this->checkAcl();
    }
}

Jakmile jako nepřihlášený uživatel zadám cestu k /ucet/, tak mě to úspěšně přesměruje na přihlašovací stránku a do URL se přidá backlink, ale jakmile se přihlásím, dostanu tuto hlášku:
Nette\InvalidStateException
Resource ‚Front:Ucet:prihlaseniForm-form‘ does not exist.

Tento resource v Ucet neexistuje, to je pravda, nicméně nevím, proč se mi tam objevuje Ucet. Už nevím jak z toho ven. Popřípadě, pokud byste měli lepší řešení pro autorizaci, byl bych rád za radu.

Děkuji.

Unlink
Člen | 298
+
0
-

Skôr keby si sem dal to prihlásenie.

Facedown
Člen | 38
+
0
-

@Unlink

<?php

namespace App\FrontModule\Presenters;

class PrihlaseniPresenter extends BasePresenter {
    /** @var \App\FrontModule\Forms\LoginFormFactory @inject */
    public $form;
    /** @persistent */
    public $backlink = '';
    /** @var \App\FrontModule\Components\FacebookLoginControlFactory @inject */
    public $facebookLoginControl;

    public function actionDefault() {
        if($this->user->isLoggedIn()) {
            $this->flashMessage('Již jsi přihlášen', 'warning');
            $this->redirect('Default:');
        }
    }

    protected function createComponentPrihlaseniForm() {
        $form = $this->form->create();
        $form->onSuccess[] = function() { $this->onSuccessLogin(); };
        return $form;
    }

    protected function createComponentFacebookLoginControl() {
        $control = $this->facebookLoginControl->create();
        $control->onSuccess[] = function() { $this->onSuccessLogin(); };
        return $control;
    }

    private function onSuccessLogin() {
        $this->flashMessage('Přihlášení bylo úspěšné', 'success');
        $this->restoreRequest($this->backlink);
        $this->redirect('Default:');
    }
}

<?php

namespace App\FrontModule\Forms;

use Nette\Application\UI\Form;
use App\BaseModule\Forms\IFormFactory;

class LoginForm extends \Nette\Application\UI\Control {
    public $onSuccess;
    private $form;
    const TEMPORARY_LOGIN = ["+ 30 minutes", true];
    const PERMANENT_LOGIN = ["+ 14 days", false];

    public function __construct(IFormFactory $f) {
        $this->form = $f;
    }

    public function render() {
        return $this['form']->render();
    }

    public function processForm(Form $form) {
        try {
            $values = $form->getValues();
            $this->sessionTimer($values);
            $this->presenter->getUser()->login($values->email, $values->password);
            $this->onSuccess();
        } catch(\Nette\Security\AuthenticationException $ex) {
            $this->presenter->flashMessage($ex->getMessage(), 'danger');
        }
    }

    private function sessionTimer($values) {
        if($this->isSetPermanentLogin($values))
            $this->presenter->getUser()->setExpiration(...self::PERMANENT_LOGIN);
        else
            $this->presenter->getUser()->setExpiration(...self::TEMPORARY_LOGIN);
    }

    private function isSetPermanentLogin($values) {
        return isset($values->remember);
    }

    protected function createComponentForm() {
        $form = $this->form->create();
        $form->addProtection();
        $this->addEmail($form);
        $this->addPassword($form);
        $this->addRemember($form);
        $form->addSubmit('signIn', 'Přihlásit');
        $form->onSuccess[] = function() use ($form) {
            $this->processForm($form);
        };
        return $form;
    }

    private function addEmail(Form $form) {
        $form->addText('email', 'E-mail')
        ->setType('email')
        ->addRule(Form::FILLED, '%label musí být vyplněn')
        ->addCondition(Form::FILLED)
        ->addRule(Form::EMAIL, '"%value" není email');
    }

    private function addPassword(Form $form) {
        $form->addPassword('password', 'Heslo')
        ->addRule(Form::FILLED, '%label musí být vyplněné');
    }

    private function addRemember(Form $form) {
        $form->addCheckbox('remember', 'Trvalé přihlášení');
    }
}

Editoval Facedown (3. 7. 2015 17:17)

Facedown
Člen | 38
+
0
-

V přípdadě, že místo rozhraní IAuthorizator tam dám přímo Permission, tak dostávám tuto chybu:

Recoverable Error

Argument 2 passed to Base\Model\Authorization::__construct() must be an instance of Nette\Security\Permission, instance of Base\Model\Authorization given, called in C:\xampp\htdocs\Argue\app\BaseModule\presenters\BasePresenter.php on line 11 and defined

Zdá se tedy, že je již nastaven ten můj authorizator, přičemž k danému setteru se ještě v kódu ani nedošlo. Vůbec nevím jak z toho.

Unlink
Člen | 298
+
0
-

Ten spôsob akým používaš ten authorizátor nebude najsprávnejší, mal by si ten svoj registrovať cez DI a tomu Permission nastaviť autowired: no

Len teraz neviem, ako by si tam dostal presenter…

Tá tvoja druhá chyba, mi pripadá tak, akoby si ten tvoj autorizátor nastavil Userovi 2× čo môže potom spôsobiť aj ten prvý problém.

Ja by som ti odporúčal, tu logiku čo máš v isAllowed presunúť do tej metódy checkAcl a môžeš potom používať ten Permission authorizator.

Facedown
Člen | 38
+
0
-

Unlink napsal(a):

Ten spôsob akým používaš ten authorizátor nebude najsprávnejší, mal by si ten svoj registrovať cez DI a tomu Permission nastaviť autowired: no

Len teraz neviem, ako by si tam dostal presenter…

Tá tvoja druhá chyba, mi pripadá tak, akoby si ten tvoj autorizátor nastavil Userovi 2× čo môže potom spôsobiť aj ten prvý problém.

Ja by som ti odporúčal, tu logiku čo máš v isAllowed presunúť do tej metódy checkAcl a môžeš potom používať ten Permission authorizator.

Pokud bych tu logiku přesunul do BasePresenteru do metody checkAcl, tak jak bych potom mohl používat Authorizator v šablonách?

Unlink
Člen | 298
+
0
-

A prečo by nefungoval? lebo nechápem načo potrebuješ v šablóne kontrolovať oprávnenia vzhľadom na aktuálny signál?

Facedown
Člen | 38
+
0
-

Unlink napsal(a):

A prečo by nefungoval? lebo nechápem načo potrebuješ v šablóne kontrolovať oprávnenia vzhľadom na aktuálny signál?

Já jsem to nezkoušel, ale co když mám takovou URL:
/www/argue/1/?argueControl-id=1&do=argueControl-like&argueControl-_sec=092ab582

Je to odkaz pro like, takže bych požadoval, že když uživatel nebude přihlášen (mít oprávnění), tak aby třeba místo odkazu byl šedý palec nebo něco v tom smyslu.

Unlink
Člen | 298
+
0
-

no ale to ani ten tvoj kód nerieši keďže kontroluje len akutálny signál $this->presenter->getSignal()

	public function isAllowed($role, $name, $action) {
    $signal = $this->presenter->getSignal();
    if($this->isSignalFromPresenter($signal))
        $action = $signal[1] . '!';
    elseif($this->isSignalFromComponent($signal)) {
        $name = $name . ':' . $signal[0];
        $action = $signal[1] . '!';
    }
    return $this->authorization->isAllowed($role, $name, $action);
}

Ako máš momentálne definované resources?

Je to odkaz pro like, takže bych požadoval, že když uživatel nebude přihlášen (mít oprávnění), tak aby třeba místo odkazu byl šedý palec nebo něco v tom smyslu.

Podľa toho treba definovať tie resorce, a potom tam pridať napríklad

{if $user->isAllowed('likeControll', 'add')}