Authentificator a DB, pomoc do začátku

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

Zdravím, už druhý den se snažím přijít na připojení k DB a authentifikaci. Prošel jsem už tunu topiců a jsem z toho nějakej mimo. Není někde nějaký topic, který fakt popisuje přesně co a jak? Jsem začátečník, tak doufám že ke mě budete shovívaví a odnesu si nějaké moudré rady aby mě to popostrčilo o kus dál.

CZechBoY
Člen | 3608
+
0
-

Co konkrétně nechápeš?
Mrkni do sandboxu na ukázkový autentikátor.
Tu třídu zaregistruješ do konfiguráku jako službu.

Merfinder
Člen | 35
+
0
-

Takže pokud si budu dělat svůj autentifikátor tak ho vytvořím a pak ho musím vložit(registrovat v configu) jako je ten nynější UserManager? A dále nechápu jak propojit tu databázi… přes toho adminera jsem si udělal databázi kde je tabulka user a v ní id,login,password,role, jenže nevím jak jí napojit :/ vím že se to dělá taky v tom configu ale už jsem toho viděl tolik že jsem z toho zmatenej :/

CZechBoY
Člen | 3608
+
0
-

Zkus si trochu proklikat ten repozitář sandboxu a třeba ti něco dojde samo :-)
Do config.local.neon se ukládá připojení k databázi. Tento soubor se většinou v repozitářích (git, svn, …) neverzuje, pouze se nahraje základní varianta jako je v sandboxu. Příklad nastavení viz dokumentace (kousek nad kapitolou dotazy).

Dále si musíš předat instanci databázové vrstvy (\Nette\Database\Context), viz konstruktor té třídy UserManager.

Editoval CZechBoY (19. 1. 2016 21:33)

Merfinder
Člen | 35
+
0
-

Dobře řekněme že ten config.local.neon mám nastavenej(dbname,user,password atd..) tím bych měl mít nastavenou databázi..... a v config.neon je zaregistrovaný autentifikátor(ten základní UserManager) a v něm jsem jen poupravil název tabulky… dále ten autentifikátor tedy obsahuje konstruktor

`	public function __construct(\Nette\Database\Context $database)
	{
		$this->database = $database;
	}`

a ten se ještě někam předává? nebo jak?

CZechBoY
Člen | 3608
+
0
-

Ten už sis správně uložil do property/soukromé třídní proměnné $this->database. Od teď už můžeš v jakékoliv nestatické (všechny metody bez označení static) metodě používat $this->database.

Pokud ta tvoje třída implementuje rozhraní IAuthenticator tak se ti sama registruje a bude se používat při loginu uživatele. Viz formulář pro přihlášení.

// $this->user je instance třídy Nette\Security\User

$this->user->login($jmeno, $heslo);
Merfinder
Člen | 35
+
0
-

Takže nemusím toto

`   public function __construct(\Nette\Database\Context $database)
    {
        $this->database = $database;
    }`

vkládat do SignPresenter, kde se přihlašuji přes formulář?

v SignPresenteru mám toto

<?php

namespace AdminModule;

use Nette;

class SignPresenter extends BasePresenter
{

       protected function beforeRender()
    {
        parent::beforeRender();
        $this->setLayout('layoutLogin');
    }


    public function renderDefault()
    {


    }




    protected function createComponentSignInForm()
{
    $form = new Nette\Application\UI\Form;

    $form->addText('username')
        ->setRequired('Prosím vyplňte své uživatelské jméno.')->setAttribute("placeholder","Uživ. jméno");

    $form->addPassword('password')
        ->setRequired('Prosím vyplňte své heslo.')->setAttribute("placeholder","Heslo");;

    $form->addSubmit('send', 'Přihlásit');

    $form->onSuccess[] = array($this, 'signInFormSucceeded');
    return $form;
}

    public function signInFormSucceeded($form)
{
        $values = $form->values;

    try {

        $this->user->login($values->username, $values->password);
        $this->redirect('Dashboard:');

    } catch (Nette\Security\AuthenticationException $e) {
        $form->addError('Nesprávné přihlašovací jméno nebo heslo.');
    }
}

    public function actionOut()
{
    $this->getUser()->logout();
    $this->flashMessage('Odhlášení bylo úspěšné.');
    $this->redirect('Sign:in');
}




}

Pořád se mi ale nedaří se přihlásit :/ hlásí pořád Nesprávné přihlašovací jméno nebo heslo.

CZechBoY
Člen | 3608
+
0
-

Nee, předávej si závislosti jen tam kde je potřebuješ. :-)

Jak máš uložená hesla v databázi? Stejně jako je kontroluješ potom?
V tom autentikátoru v sandboxu je i metoda na přidání uživatele add, která přidá nového uživatele – obstará zahashování hesla a vyhazuje výjimku pokud uživatel s tím emailem už existuje.

Editoval CZechBoY (19. 1. 2016 23:25)

Merfinder
Člen | 35
+
0
-

Já jsem si rovnou v pro ty účty v DB zahashoval ty hesla.

Editoval Merfinder (20. 1. 2016 0:08)

CZechBoY
Člen | 3608
+
0
-

Pomocí stejné funkce jako je kontroluješ v metodě authenticate?

Jsou ty hashe určitě stejně dlouhé? Nemáš v db třeba ten sloupec kratší o pár znaků než je vygenerovaný hash?

Merfinder
Člen | 35
+
0
-

Tak jsem z toho ještě víc na větvi :/ :D …ale jestli to dobře chápu, tak to hashování může být jiné než to v DB? je to tak ne?

CZechBoY
Člen | 3608
+
0
-

Porovnáváš hash a hash.

  1. uživatel zadá heslo (plain text)
  2. ty ho zahashuješ
  3. porovnáš s hashem v databázi
  4. pokud sedí tak ok, jinak je špatně zadané heslo od uživatele

Mrkni kolik znaků ti vygeneruje ta hashovací metoda a zkontroluj jestli se ti vyjde do sloupce v databázi.

Merfinder
Člen | 35
+
0
-

tak to budu asi potřebovat zaregistrovat nového uživatele?

CZechBoY
Člen | 3608
+
0
-

Je jedno jak vygenerujes ten hash uzivatele.
Idealne zalozit novyho uzivatele metodou add – v pripade ze chces pouzivat ten Nette hash.

Kolik znaku ma sloupec na heslo v tvoji db?

Merfinder
Člen | 35
+
0
-

Tak jsem zprovoznil add metodu a uživatele to přidá, každý dostane username,password a role …sloupec na heslo mám varchar(255), takže by se to tam mělo vejít …jenže pořád zlobí to přihlášení :/

CZechBoY
Člen | 3608
+
0
-

Hm. Tak si vypis jakej hash ti to vrati pri prihlasovani a porovnej vlastnim okem s tim co je v databazi.

Merfinder
Člen | 35
+
0
-

Nějak jsem to pošteloval a jde :D …ještě bych si chtěl ujasnit, když vytvářím to připojení k databázi a používám to teda u toho autentifikátoru viz.

	/** @var Nette\Database\Context */
	public $database;


	public function __construct(\Nette\Database\Context $database)
	{
		$this->database = $database;
	}

a pak potřebuju připojení k databázi třeba když vypisuji články, tak co mám použit? znovu ten kód v presenteru s články nebo existuje něco globálního?

CZechBoY
Člen | 3608
+
0
-

Predej si to pres konstruktor zase no.

Potom tu tridu muzes podedit aby si nemusel porad ten konstruktor psat.

use Nette\Database\Context;

abstract class BaseDb
{
    protected $database;

    public function __construct (Context $database)
    {
        $this->database = $database;
    }
}

Potom clankovy repozitar

class ArticleRepository extends BaseDb
{
    public function getBySlug ($slug)
    {
        return $this->database
            ->table('article')
            ->where('slug', $slug);
    }
}

A do konfiguraku config.neon registrujes pouze ArticleRepository.

Editoval CZechBoY (20. 1. 2016 18:28)

Merfinder
Člen | 35
+
0
-

Tady ten ArticleRepository můžu použít i pro obecné vybíraní z DB? Třeba že bych ho pojmenoval napr. VybiraniRepository a měl v něm metody pro vybírání uživatelů, článků atd…?

CZechBoY
Člen | 3608
+
0
-

Můžeš, ale určitě to nedoporučuju.
Radši udělej tisíc tříd s 1–2 metodama, aby si v tom měl pořádek.

Merfinder
Člen | 35
+
0
-

Ok takže vytvořím to připojení, od něho budu dědit ruzné repozitáře, které budou pracovat s db a ty si zaregistruju v configu. Z nich pak tedy můžu používat metody pokud to vše dobře chápu?

Merfinder
Člen | 35
+
0
-

Ještě jakým způsobem ty metody můžu volat?

chemix
Nette Core | 1310
+
0
-

@Merfinder muzu se zeptat? Zkousel jsi si projit Quick startem? Narazil jsi tam na nejky problem? Nebo vse slo podle planu?

Merfinder
Člen | 35
+
0
-

Prošel jsem to docela bez obtíží… jenže si to chci implementovat na svém systému a jak jsem procházel ty topicy tak to chci poskládat do nějaké jiné formy než té základní, různě jsem koukal jak a co kdo dělá atd…

Merfinder
Člen | 35
+
0
-

Snažím se vypsat uživatele, ale nedaří se, pokouším se dodržet ten postup co je v quickstartu ale je problém s tou proměnnou $posts jako z quickstrtu…

UserRepository.php

<?php

namespace App\Model;

use Nette,
    App\Model;

class UserRepository extends BaseDb
{

    public function getUsers()
    {
        return $this->database->table('users')->order('username DESC');
    }

}

UsersPresenter.php

/**
    * @var \App\Model\UserRepository
    * @inject
    */
    public $model;



    public function renderDefault()
    {
        $this->template->users = $this->model->getUsers();

    }

template show.latte

<div n:foreach="$users as $user" class="post">
    <div class="username">{$user->username}</div>
</div>

config.neon

services:
        - App\Forms\SignFormFactory
        - App\Model\UserAuth
        - App\Model\UserRepository
        router: App\RouterFactory::createRouter

problém je s tou proměnnou $users, nechápu co mám dát tam jak je $this->template->????

CZechBoY
Člen | 3608
+
0
-

Co oznacis jako public tak muzes pouzivat zvenku – z presenteru, komponenty, jiny tridy proste.

Ten ArticleRepository si potom v presenteru, komponente, jiny tride vyzadas pres konstruktor.

CZechBoY
Člen | 3608
+
0
-

Vypada to na prvni pohled v poradku. Nepouzival bych asi promennou $user, protoze tam se uklada uzivatel z Nette (aktualne prihlaseny uzivatel).

Jaka je chybova hlaska, co nejde?

Merfinder
Člen | 35
+
0
-

No stránka se mi zobrazí normálně ale dole Tracy jsou dva errory

  1. PHP Notice: Undefined variable: users in D:\Programy\XAMPP\htdocs\TestCMS\sandbox\temp\cache\latte\sandbox-app-AdminModule-templates-Users-show-latte-Templated87688856cc8c76359e49b977877a00d.php:23
  2. PHP Warning: Invalid argument supplied for foreach() in D:\Programy\XAMPP\htdocs\TestCMS\sandbox\temp\cache\latte\sandbox-app-AdminModule-templates-Users-show-latte-Templated87688856cc8c76359e49b977877a00d.php:23
Merfinder
Člen | 35
+
0
-

joo blbě jsem refreshul laděnka tohle Undefined variable $users, did you mean $user?

David Matějka
Moderator | 6445
+
0
-

Jelikoz volas akci show, ale plnis to v renderDefault, coz je pro akci default. takze jen prejmenuj tu metodu na renderShow

Merfinder
Člen | 35
+
0
-

Nice funguje :)) díky moc vše za pomoc, zase budu otravovat jindy, dost jste mi pomohli s takovou tou základní funkcionalitou co a jak :) sem vám vděčný :) ještě jednou díky :)

Gl4dr
Člen | 7
+
0
-

Zdravím, řeším podobný problém. Prošel jsem si důkladně tuto diskuzi a stále mi přihlašování nefunguje. Kontroloval jsem HASH otisky, přístup do databáze i vypsání dat z ní. Mělo by to fungovat, akorát pokaždé po zadání jména a hesla mi to napíše „Nesprávné přihlašovací jméno nebo heslo.“ poradíte mi někdo co s tím dělat? Vše jsem se pokusil nastavit stejně jako v tomto tématu, a mělo by to tak být.

chemix
Nette Core | 1310
+
0
-

@Gl4dr zkus dat na github tvuj sandbox

Gl4dr
Člen | 7
+
0
-

@chemix Celou složku s projektem???

CZechBoY
Člen | 3608
+
0
-

@Gl4dr Složka App by měla stačit. Složka vendor není potřeba pokud si nic neměnil.

Gl4dr
Člen | 7
+
0
-

Tak jsem to uploadnul. Kdyžtak na to koukněte. Asi tam budou nějaký nesmysly, jak jsem testoval.

https://github.com/…uth/issues/1

CZechBoY
Člen | 3608
+
0
-

@Gl4dr Určitě máš v databázi uložené správné údaje? Máš dostatečnou délku sloupce na heslo?

Moc nechápu proč si debuguješ md5 hash, když kontrola se provádí proti úplně jiné hashovací funkci.
Jo a určitě by bylo lepší dát na github ty soubory přímo a ne zip do issues :-)

Gl4dr
Člen | 7
+
0
-

@CZechBoY A proti jaké funkci kontrola probíhá? To bude možná tím, já si zadal md5 i v databázi. jinak sloupec v databázi má 255 takže asi jo.

CZechBoY
Člen | 3608
+
0
-

Pro pridani uzivatele pouzij metodu add v tom UserManageru.

Gl4dr
Člen | 7
+
0
-

Je to sice blbej dotaz, ale jsem docela začátečník. Udělal jsem si stejnej formulář jako je sign in. A když se ho snažím zavolat vyhodí to error Call to a member function add() on null

upravenej kus SignPresenteru

<?php
 protected function createComponentRegisterForm()
{
    $roles = array(
                    'comp1' => 'Company 1',
                    'comp2' => 'Company 2',
                    'comp3' => 'Company 3',
                );

                $form = new Nette\Application\UI\Form;
        $form->addText('username', 'Username:')
            ->setRequired('Please enter your username.');

        $form->addPassword('password1', 'Password:')
            ->setRequired('Please enter your password.');

                $form->addPassword('password2', 'Password again:')
            ->setRequired('Please enter your password.');


                $form->addRadioList('radio2', 'Select your company:', $roles);

        $form->addSubmit('send', 'Register');

        //call method registerFormSucceeded() on success
        $form->onSuccess[] = $this->registerFormSucceeded;
        return $form;
}

    public function registerFormSucceeded($form)
{
       $values = $form->getValues();



                    $this->UserManager->add($values->username, $values->password, $values->radio2);
                    $this->flashMessage('You have been registered succesfuly.');

}
?>

a muj UserManager

<?php


namespace App\Model;

use Nette;
use Nette\Security\Passwords;


/**
 * Users management.
 */
class UserManager extends Nette\Object implements Nette\Security\IAuthenticator
{
	const
		TABLE_NAME = 'uzivatele',
		COLUMN_ID = 'ID_Uzivatel',
		COLUMN_NAME = 'Jmeno',
		COLUMN_PASSWORD_HASH = 'heslo',
		COLUMN_ROLE = 'role';


	/** @var Nette\Database\Context */
	private $database;


	public function __construct(Nette\Database\Context $database)
	{
		$this->database = $database;
	}


	/**
	 * Performs an authentication.
	 * @return Nette\Security\Identity
	 * @throws Nette\Security\AuthenticationException
	 */
	public function authenticate(array $credentials)
	{
		list($username, $password) = $credentials;

		$row = $this->database->table(self::TABLE_NAME)->where(self::COLUMN_NAME, $username)->fetch();

		if (!$row) {
			throw new Nette\Security\AuthenticationException('The username is incorrect.', self::IDENTITY_NOT_FOUND);

		} elseif (!Passwords::verify($password, $row[self::COLUMN_PASSWORD_HASH])) {
			throw new Nette\Security\AuthenticationException('The password is incorrect.', self::INVALID_CREDENTIAL);

		} elseif (Passwords::needsRehash($row[self::COLUMN_PASSWORD_HASH])) {
			$row->update(array(
				self::COLUMN_PASSWORD_HASH => Passwords::hash($password),
			));
		}

		$arr = $row->toArray();
		unset($arr[self::COLUMN_PASSWORD_HASH]);
		return new Nette\Security\Identity($row[self::COLUMN_ID], $row[self::COLUMN_ROLE], $arr);
	}


	/**
	 * Adds new user.
	 * @param  string
	 * @param  string
	 * @return void
	 */
	public function add($username, $password, $role)
	{
		try {
			$this->database->table(self::TABLE_NAME)->insert(array(
				self::COLUMN_NAME => $username,
				self::COLUMN_PASSWORD_HASH => Passwords::hash($password),
        self::COLUMN_ROLE => $role,
			));
		} catch (Nette\Database\UniqueConstraintViolationException $e) {
			throw new DuplicateNameException;
		}
	}

}



class DuplicateNameException extends \Exception
{}
?>
premek_k
Člen | 172
+
0
-

Vypadá to, že sis do toho presenteru zapomněl injektnout ten manager.

Gl4dr
Člen | 7
+
0
-

@premek_k Zavedený tam ten UserManager je

<?php
<?php

namespace App\Presenters;

use Nette;
use App\Forms\SignFormFactory;
use Nette\Database\Context;
use App\model\UserManager;

class SignPresenter extends BasePresenter
{

   /*    protected function beforeRender()
    {
        parent::beforeRender();
        $this->setLayout('layoutLogin');
    } */
    private $database;
    public $UserManager;
    public function renderDefault()
    {


    }




    protected function createComponentSignInForm()
{
    $form = new Nette\Application\UI\Form;

    $form->addText('username')
        ->setRequired('Prosím vyplňte své uživatelské jméno.')->setAttribute("placeholder","Uživ. jméno");

    $form->addPassword('password')
        ->setRequired('Prosím vyplňte své heslo.')->setAttribute("placeholder","Heslo");;

    $form->addSubmit('send', 'Přihlásit');

    $form->onSuccess[] = array($this, 'signInFormSucceeded');
    return $form;
}

    public function signInFormSucceeded($form)
{
        $values = $form->values;

    try {

        $this->user->login($values->username, $values->password);
        $this->redirect('Dashboard:');

    } catch (Nette\Security\AuthenticationException $e) {
        $form->addError('Nesprávné přihlašovací jméno nebo heslo.');
        $form->addError(hash('md5',$values->password));
    }
}

    public function actionOut()
{
    $this->getUser()->logout();
    $this->flashMessage('Odhlášení bylo úspěšné.');
    $this->redirect('Sign:in');
}









 protected function createComponentRegisterForm()
{
    $roles = array(
                    'comp1' => 'Company 1',
                    'comp2' => 'Company 2',
                    'comp3' => 'Company 3',
                );

                $form = new Nette\Application\UI\Form;
        $form->addText('username', 'Username:')
            ->setRequired('Please enter your username.');

        $form->addPassword('password1', 'Password:')
            ->setRequired('Please enter your password.');

                $form->addPassword('password2', 'Password again:')
            ->setRequired('Please enter your password.');


                $form->addRadioList('radio2', 'Select your company:', $roles);

        $form->addSubmit('send', 'Register');

        //call method registerFormSucceeded() on success
        $form->onSuccess[] = $this->registerFormSucceeded;
        return $form;
}

    public function registerFormSucceeded($form)
{
       $values = $form->getValues();



                    $this->UserManager->add($values->username, $values->password, $values->radio2);
                    $this->flashMessage('You have been registered succesfuly.');

}
}

?>
premek_k
Člen | 172
+
+1
-

Takto jsi definoval jen veřejnou třídní property. Musíš nad tu definici dopsat ještě @inject anotaci.

premek_k
Člen | 172
+
0
-
/**
 * @var \App\Model\UserRepository @inject
 */
 public $UserManager;
Gl4dr
Člen | 7
+
0
-

Tak jsem to tam přidad a pro změnu je tu další Error

Class or interface ‚App\Model\UserRepository‘ used in @var annotation at App\Presenters\SignPresenter::$UserManager not found. Check annotation and ‚use‘ statements.

Tanadche
Člen | 11
+
+1
-

Máš špatný název třídy ve var anotaci. Podle předchozích ukázek kódu se tvá třída jmenuje UserManager a ne UserRepository. Zkus to takhle upravit:

/**
 * @var \App\Model\UserManager @inject
 */
 public $UserManager;