Nefunkční authenticator a přihlašování pomocí databáze

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

Zdravím,
jsem začátečník a mám problém s authentikátorem, v podstatě jsem se držel toho co je v sandboxu i problému který se řešil zde
https://forum.nette.org/…uthenticator. Při použití SimpleAuthenticatoru viz

$authenticator = new Nette\Security\SimpleAuthenticator(array(
            'john' => 'john',
            'dad' => 'dad'
        ));

mi vše funguje bez problému ale potřebuji vyřešit přihlašování pomocí databáze.

MyAuthenticator.php

use Nette\Security as NS;

class MyAuthenticator extends Nette\Object implements NS\IAuthenticator
{
    public $database;

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

    function authenticate(array $credentials)
    {
        list($username, $password) = $credentials;
        $row = $this->database->table('users')
            ->where('username', $username)->fetch();

        if (!$row) {
            throw new NS\AuthenticationException('User not found.');
        }

        if (!NS\Passwords::verify($password, $row->password)) {
            throw new NS\AuthenticationException('Invalid password.');
        }

        return new NS\Identity($row->id, $row->role, array('username' => $row->username));
    }
}

Config.neon

#
# WARNING: it is CRITICAL that this file & directory are NOT accessible directly via a web browser!
# https://nette.org/en/security-warning
#
parameters:
        database:
            driver: mysql
            host: xx
            dbname: xx
            user: xx
            password: xx


php:
	date.timezone: Europe/Prague


application:
	errorPresenter: Error
	mapping:
		*: App\*Module\Presenters\*Presenter

session:
	expiration: 14 days


services:
  database: @Nette\Database\Connection
  router: App\RouterFactory::createRouter
  authenticator: MyAuthenticator( @database )

SignInPresenter.php

namespace App\Presenters;
use Nette,
	Nette\Application\UI\Form;

/**
 * Sign in/out presenters.
 */
class SignPresenter extends BasePresenter
{

	/**
	 * Sign-in form factory.
	 * @return Nette\Application\UI\Form
	 */
  protected function createComponentSignInForm()
  {
      $form = new Form();
      $form->addText('username', 'Uživatelské jméno:')
          ->setRequired('Prosím vyplňte své uživatelské jméno.');

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

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

      $form->onSuccess[] = $this->signInFormSucceeded;
      return $form;
  }

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

		if ($values->remember) {
			$this->getUser()->setExpiration('7 days', TRUE);
		} else {
			$this->getUser()->setExpiration('120 minutes', TRUE);
		}

		$user->setAuthenticator($this->context->getService('authenticator'));

		try {
			$this->getUser()->login($values->username, $values->password);
			$this->redirect('Homepage:');

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


	public function actionOut()
	{
		$this->getUser()->logout();
		$this->redirect('default');
	}

Dostal jsem se do fáze kde mám auth. zaregistrovány i ho používám ale na této řádce se to zastaví s tímto errorem

$row = $this->database->table('users')
Nette\MemberAccessException

Call to undefined method Nette\Database\Connection::table().

Možná je to fakt úplně blbost, ale už jsem vyzkoušel skoro vše a nevím si rady. Díky za odpovědi.

Editoval Danny (26. 2. 2016 17:56)

CZechBoY
Člen | 3608
+
0
-

Vyzadej v konstruktoru Context a ne Connection.

Danny
Člen | 146
+
0
-

To když udělám tak právě dostanu chybu

Argument 1 passed to MyAuthenticator::__construct() must be an instance of Nette\Database\Context, instance of Nette\Database\Connection given, called in /data/web/virtuals/119138/virtual/www/xx/temp/cache/Nette.Configurator/Container_336f31a05f.php on line 394 and defined
premek_k
Člen | 172
+
+1
-

Ten config.neon máš nestandardně. V registraci toho Authenticatoru neuváděj ten parametr @database. A celá ta sekce Database nemá být zanořená v Parameters.

Danny
Člen | 146
+
0
-

Tak jsem to upravil jak si psal

nette:
    database:
        dsn: 'xx;dbname=xx'
        user: xx
        password: xx
        options:
            lazy: yes

a odstranil parametr @database, ale problém stále přetrvává :/

Danny
Člen | 146
+
0
-

Ještě jsem zkusil vyžádat context místo connection v tom konstruktoru a přihlášování trvá dlouho a pak mi vyskočí chyba

SQLSTATE[HY000] [2003] Can't connect to MySQL server on '127.0.0.1' (4 "Interrupted system call")

což je divné protože se nepřipojuju na na local ale na hosting na wedosu, kde běží i aplikace.

CZechBoY
Člen | 3608
+
0
-

Mas urcite spravne dsn?

Danny
Člen | 146
+
0
-

Mám, přes tyto údaje se normálně připojim k DB.

dsn: 'mysql:host=wm104.wedos.net;dbname=d119138_bak'

Editoval Danny (26. 2. 2016 19:24)

CZechBoY
Člen | 3608
+
+1
-

Nejedes na produkcnim rezimu? Zkus smazat cache.

Danny
Člen | 146
+
0
-

Tak jsem tak projížděl bootstrap a odkomentoval sem aby se nenačítal congic.neon.local a pomohlo to. Moje chyba, netušil sem že by to tomu mohlo vadit asi se bral jako defaultní a snažilo se to připojit k localu. Nicméně se mi provádí už kontrola zda user existuje akorát se mi při chybě nevyhazuje expection což je zvláštní. Díky za rady :)

CZechBoY
Člen | 3608
+
0
-

Protoze tu vyjimku chytas. Nebude to tim? Nebo kde bys ji chtel chytat?

Danny
Člen | 146
+
0
-

No v podstatě myslím zde

$row = $this->database->table('users')
    ->where('username', $username)->fetch();

if (!$row) {
    throw new NS\AuthenticationException('User not found.');
}

if (!NS\Passwords::verify($password, $row->password)) {
    throw new NS\AuthenticationException('Invalid password.');
}

že to nevypíše ani hlášku „user not found“. Trochu mě zaráží SQL dotaz v laděnce když zadám existujícího uživatele, kde se vybírá pouze ID a pass a pak se porovnává username.

SELECT `id`, `password`
FROM `users`
WHERE (`username` = 'zadanejmeno')
CZechBoY
Člen | 3608
+
0
-

A co si ulozi do role a username?
Tak tady se vyhazujou vyjimky, chytas je ve formulari.

Danny
Člen | 146
+
0
-

Jo díky už sem si to vše vypsal, chyby se vypisují správně ale mám pocit že bych měl mít v laděnce vidět 2 sql query jak na username tak na password a je tam pořád to jedno. Nicméně potřeboval bych zjistit jak pracuje funce verify, předpokládám že hashuje to heslo a kontroluje zda souhlasí s tím co je v DB, takže sem do DB vložil hashnuté heslo pomocí MD5 ale neshoduje se, potřeboval bych vidět jak vypadá ten algoritmus zda je tam i salt atd.

premek_k
Člen | 172
+
0
-

Nene, query bude jen jedno – omezené dle username. Pokud se z db nevrátí žádný záznam where username = 'onojmeno', tak to znamená, že uživatel s tímto username není v db. A pokud se vrátí, tak se zkontroluje právě to vrácené heslo tím selektem s heslem, které přišlo z formuláře. Roger?

Jo, a zkontroluj si, zda nemáš „malý“ sloupec pro password v té tabulce – tzn. zda se ti uložilo celé.

Editoval premek_k (26. 2. 2016 21:09)

Danny
Člen | 146
+
0
-

Aha chápu díky :) sloupec pro password mám na char(60) a je tam uložené celé.

Danny
Člen | 146
+
0
-

Toto mi stále vrací Invalid password, nechal sem si vyjet i $password a $row->password zvlášť a obsahuje to přesně ty hodnoty které by mělo, input z formu a hash heslo z db. Je možný že je něco špatně s funkci verify?

if (!NS\Passwords::verify($password, $row->password)) {
    throw new NS\AuthenticationException('Invalid password. Heslo z formu'.$password.'.Hash heslo z DB'.$row->password);
}
premek_k
Člen | 172
+
0
-

Koukni sem, tady máš jak tu verify, tak i hash.
Na hashování hesla se používá crypt.

Danny
Člen | 146
+
0
-

Vyřešeno, děkuji za rady :)