Nefunkční authenticator a přihlašování pomocí databáze
- Danny
- Člen | 146
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)
- Danny
- Člen | 146
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
- Danny
- Člen | 146
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.
- Danny
- Člen | 146
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 :)
- Danny
- Člen | 146
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')
- Danny
- Člen | 146
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
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
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);
}