Dvě aplikace na stejnem serveru by měly mít rozdílné přihlášení

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

Zdravím. Mám dvě rozdílné modulární aplikace (momentálně na localhostu), v obou mám administrační část, do které je třeba se přihlásit. Ovšem když se v jedné přihlásím, tak jsem pak přihášen i v té druhé pod útem z té první aplikace (i když ve druhé aplikaci využívam pro ověření prihlášení data z jiné databáze). Jak tohle řešíte?

Přihlášení se vlastně ověřuje jako isAuthenticated() a pokud je, tak se vezme getIdentity().

Ať neplácám do větru lépe to znárotním kódem:

class Admin_BasePresenter extends BasePresenter
{
	protected function beforeRender()
	{
	        parent::beforeRender();

		$user = Environment::getUser();
		$this->template->user = $user->isAuthenticated() ? $user->getIdentity() : NULL;
	}
}

// z tohoto preseneru dedi ostani presentery, ktere jsou pristupne az po prihlaseni
class Admin_SecuredBasePresenter extends Admin_BasePresenter
{
    protected function startup()
    {
	parent::startup();

        // user authentication
        $user = Environment::getUser();
        if (!$user->isAuthenticated()) {
            if ($user->getSignOutReason() === User::INACTIVITY) {
                $this->flashMessage('Byl jste automaticky odhlášen z důvodu dlouhé neaktivitě. Přihlašte se prosím znova.');
            }
            $backlink = $this->getApplication()->storeRequest();
            $this->redirect('Auth:login', array('backlink' => $backlink));
        }
    }

    public function actionLogout()
    {
        Environment::getUser()->signOut();
        $this->flashMessage('Byl jste odhlášen.');
        $this->redirect('Auth:login');
    }
}

class Admin_AuthPresenter extends Admin_BasePresenter
{
	/** @persistent */
	public $backlink = '';

	protected function createComponentLoginForm()
	{
		$form = new AppForm();

		$form->addText('username', 'Uživatel:')->addRule(Form::FILLED, 'Vložte uživatelské jméno.');
		$form->addPassword('password', 'Heslo:')->addRule(Form::FILLED, 'Vložte heslo.');
		$form->addSubmit('login', 'Přihlásit');
		$form->addProtection('Prosím odešlete přihlašovací údaje znova (vypršla platnost tzv. bezpečnostního tokenu).');
		$form->onSubmit[] = callback($this, 'loginFormSubmitted');

		return $form;
	}

	public function loginFormSubmitted($form)
	{
		try {
			$user = Environment::getUser();
			$user->authenticate($form['username']->getValue(), $form['password']->getValue());
			$this->getApplication()->restoreRequest($this->backlink);
			$this->redirect('News:');

		} catch (AuthenticationException $e) {
			$form->addError($e->getMessage());
		}
	}
}

Co je pottřeba zmenit, aby se nějak odlišily takto vytvářená přihlášení ve dvou různých aplikacích? Měl jsem za to, že pokud jsou data o přihášení ukádána někde v session, tak jsou pro každou aplikaci nějak odlišena nějakým unikátním klíčem a každá aplikace si ze session tahá jen ta data, která jsou pro danou aplikaci přidružená. Nebo jsem úplně vedle? Díky.

Endrju
Člen | 147
+
0
-

Díky. Částečně mě to asi nakoplo..

Chci si ověřit, zda to dělám správně.
V první modulární aplikaci (výše zmíňená) jsem to ošetřil tak, že jsem v AuthPresenteru v metodě loginFormSubmitted() zaměnil v bloku try{...} řádek $user = Environment::getUser(); za $user = Environment::getUser()->setNamespace('aplikace1');.

A v SecuredBasePresenteru v metodě startup() jsem zaměnil řádek $user = Environment::getUser(); za $user = Environment::getUser()->setNamespace('aplikace1');.

Aplikace jsou nyní rozlišeny. Je to takto v pořádku nebo něco opomíjím či nedělám dobře?


No a pak jsem chtěl stejným způsobem odlišit i tu druhou modulární aplikaci. Ta se ale liší v tom, že využíva role a napsaná je podle tutoriálu na ACL

Tam jsem provedl stejné úpravy, tedy v AuthPresenteru jsem zaměnil řádek $user = Environment::getUser(); za $user = Environment::getUser()->setNamespace('aplikace2');.

A v SecuredPresenteru v metodě startup() jsem zaměnil řádek $user = Environment::getUser()->setAuthorizationHandler(new Proj_Security_Acl()); za $user = Environment::getUser()->setAuthorizationHandler(new Proj_Security_Acl())->setNamespace('aplikace2');.

V té druhé aplikaci mi tohle řešení ale nefunguje a při pokusu o přihlášení jsem vždy přesměrován zpět na stejnou (login) stránku. Nevíte v čem je problem?

PS: to, že to nefunguje v té druhé aplikaci mě pak přivedlo na otázku, jestli jsem to upravil dobře i v té první aplikaci?

Endrju
Člen | 147
+
0
-

Problém vyřešen, při procházení kódu té ACL aplikace jsem stéle přehlížel jednu věc a díky tomu, že kód je v těch místech téměř totožný.

V SecuredPreseneru je takřka identický kód metody startup() jako v DefaultPresenteru a já nastavoval namesapce jen v SecuredPreseneru. Logicky jsem pak přišel na to že, když po zakomentování té části kódu v SecuredPreseneru, mě to stále přesměrovává na Login, musí být přesměrování ještě někde jinde a pak mi to docvaklo úplně.

_Martin_
Generous Backer | 679
+
0
-

Především je fajn pro každou appku nastavit vlastní úložiště session a potom k takovým problémům nebude docházet=)

Endrju
Člen | 147
+
0
-

Martine, naprosto s tebou souhlasim. Tohle jsem se ale bohuzel v zadnem tutorialu nebo QuickStartu nedozvedel a pak jsem byl prekvapeny, ze to nejde podle ocekavani.. Vlastne jsem vychazel z modularni aplikace (tam sice zadna autorizace neni, tak okej no), ale treba v tom ACL tutorialu od srigiho by se uz neco takoveho hodilo..

Holt chybela vstupni informace, ktera se tykala nastavovani namespace pro aplikaci.

No a obecne pro jakoukoli aplikaci, kdyby to slo resit tak, ze by se nastavovalo umisteni session hnedka nekde v base presenteru uz i ve skeletonu (treba s patricnym komentarem), tak by to asi pak usetrilo nejakou praci hm..?

Coz me privadi na otazku: kdyz mam odlisenou namespace v autorizacnim procesu, tak asi neodstinim kompletne data front modulu tech aplikaci ktera jsou v session co? Coz asi taky neni uplne dobre. Nemam ale prilis jasno v tom jak je to ve frameworku udelano.. Zda jsou nebo nejsou ta data mezi ruznymi aplikacemi nejak stinena..? A jak to udelat – ted mam na mysli konkretni funkce (ne teoreticky rozbor)

pekelnik
Člen | 462
+
0
-

A jak to udelat – ted mam na mysli konkretni funkce (ne teoreticky rozbor)

Konkrétně je třeba nastavit session.save_path na různé adresáře u obou aplikací.

  • app2/sessions
  • app1/sessions

Nyní jsou pravděpodobně oboje sessions třeba v /tmp

  • tmp

Takže nastane situace:

  1. Přihlásím se do aplikace A – obdržím session cookie
  2. S touto cookie přistoupím do aplikace B
  3. Aplikace B nastartuje existující session podle cookie z aplikace A

Pokud budou úložiště oddělená tohle se nestane.

David Grudl
Nette Core | 7780
+
0
-

Coz me privadi na otazku: kdyz mam odlisenou namespace v autorizacnim procesu, tak asi neodstinim kompletne data front modulu tech aplikaci ktera jsou v session co? Coz asi taky neni uplne dobre.

Nejsnažší je použít jiné session ID, viz Nette\Web\Session::setName()

Endrju
Člen | 147
+
0
-

David Grudl napsal(a):

Coz me privadi na otazku: kdyz mam odlisenou namespace v autorizacnim procesu, tak asi neodstinim kompletne data front modulu tech aplikaci ktera jsou v session co? Coz asi taky neni uplne dobre.

Nejsnažší je použít jiné session ID, viz Nette\Web\Session::setName()

Trosku jsem hledal na foru, ale mozna ne podle vhodnych klicovych slov.. Bude to trivialni, ale nevim jak to udelat, aby mi ladenka cela necervenala :).

V BasePresenteru v BeforeRender mam:

if (!Environment::getSession()->isStarted()) {
	Environment::getSession()->start();
}

Zkousel jsem tam napsat Session::setName('nazev');, ale to se ji nelibi. A pak me zajima jesli musism, kdyz volam getSession() zadavat nazev te session? Nebo to funguje tak, ze kdyz uz nazev session nastavim, tak pro celou aplikaci zustava ten nazev nastaveny? Tudiz pak nemusism psat getSession(‚nazev‘)?

_Martin_
Generous Backer | 679
+
0
-

Následující kód mám v bootstrapu. Pokud máš společný APP_DIR, budeš si to řešení muset trochu upravit.

$session = Environment::getSession();
$session->setSavePath(APP_DIR . '/sessions/');
$session->start();
bazo
Člen | 620
+
0
-

session_name musis volat vzdy ako prve, vid http://php.net/…ion-name.php

Endrju
Člen | 147
+
0
-

_Martin_ napsal(a):

Následující kód mám v bootstrapu. Pokud máš společný APP_DIR, budeš si to řešení muset trochu upravit.

$session = Environment::getSession();
$session->setSavePath(APP_DIR . '/sessions/');
$session->start();

Diky