Service of type Nette\Security\IAuthenticator not found
- mistm
- Člen | 25
Z duvodu opraveneho bugu v Nette se snazim prejit na novou verzi. Prekopal jsem konfigurak a bootstrap a dostal se pres nejruznejsi chybove hlasky, az jsem se zasekl na teto:
Service of type Nette\Security\IAuthenticator not found.
Povetsinou z githubu a z dokumentace se snazim slozit spravnou konfiguraci Authenticatoru a configu, ale nedari se. Netusi nekdo prosim, kde je zakopany pes? Diky.
app/models/Authenticator.php:
<?php
namespace Model;
use Nette,
Nette\Utils\Strings;
class Authenticator extends Nette\Object implements NS\IAuthenticator
{
/** @var Nette\Database\Connection */
private $database;
public function __construct(Nette\Database\Connection $database)
{
$this->database = $database;
}
/**
* Performs an authentication
* @param array
* @return Nette\Security\Identity
* @throws Nette\Security\AuthenticationException
*/
public function authenticate(array $credentials)
{
list($username, $password) = $credentials;
$row = $this->database->table('users')->where('username', $username)->fetch();
if (!$row) {
throw new NS\AuthenticationException("Špatná kombinace uživatelského jména a hesla.", self::IDENTITY_NOT_FOUND);
}
echo $this->calculateHash($password, $username);
if ($row->password !== $this->calculateHash($password, $username) || $row->disabled==1) {
throw new NS\AuthenticationException("Špatná kombinace uživatelského jména a hesla.", self::INVALID_CREDENTIAL);
}
unset($row->password);
return new NS\Identity($row->id_user, "user", $row->toArray());
}
/**
*
* Gets username by his id.
*
* @param int $id id of user we want to know
* @return string username
*/
public static function getUsernameById($id)
{
return dibi::select('username')->from('users')->where('id_user=%i', $id)->fetchSingle();
}
/**
* Computes salted password hash.
* @param string password
* @return string hash salted by username
*/
public static function calculateHash($password, $username)
{
return md5($password . 'salt' . $username);
}
}
?>
app/config.neon:
php: # PHP configuration
date.timezone: Europe/Prague
# session.save_path: "%tempDir%/sessions"
# zlib.output_compression: yes
nette:
debugger:
strictMode: true
bar:
- @sessionPanel
session:
autoStart: smart
expiration: +5 days
services:
robotLoader:
run: true
database:
class: Nette\Database\Connection('mysql:host=localhost;dbname=databaze', 'user', 'pass')
model:
class: Model
arguments: [@database]
authenticator:
create: Authenticator( @database )
polozkyOpravy:
class: PolozkyOpravy
arguments: [@session]
sessionPanel:
class: SessionPanel
arguments:
- @application
- @session
factories:
development:
parameters:
language: 'cs'
currency: 'Kč'
database:
driver: mysql
host: localhost
database: databaze
username: user
password: pass
profiler: TRUE
charset: utf8
- mistm
- Člen | 25
Zkusil jsem, ale porad to same. Doplnim jeste, ze pouzivam aktualni verzi z webu – tzn. Nette Framework 2.0.8 stabilní, uvolněný 1. 1. 2013. Chybu ukazuje ladenka v Nette\Security\User.php:177:
return $this->authenticator ?: $this->context->getByType('Nette\Security\IAuthenticator');
V call stacku vidim posledni muj kod v SignPresenter.php v metode odeslani prihlasovaciho formulare:
$this->getUser()->login($values->username, $values->password);
Jeste jedna poznamka – musel jsem vypnout nastaveni delky session pro uzivatele tzn:
if ($values->remember) {
$this->getUser()->setExpiration('+ 14 days', FALSE);
} else {
$this->getUser()->setExpiration('+ 1 day', TRUE);
}
Protoze mi to hazelo vyjimku: The expiration time is greater than the session expiration 10800 seconds. Pritom session v konfiguraku nastavuji (prebral jsem to tusim z dokumentace, protoze jsem to tam predtim nemel). Mozna by to mohlo vest k nalezeni problemu.
Editoval mistm (20. 1. 2013 14:26)
- mistm
- Člen | 25
To by znelo logicky, nicmene nepomohlo. Pro jistotu jsem v kodu napsal napevno vsude Nette\Security\IAuthenticator:
<?php
namespace Model;
use Nette,
Nette\Utils\Strings;
class Authenticator extends Nette\Object implements Nette\Security\IAuthenticator
{
/** @var Nette\Database\Connection */
private $database;
public function __construct(Nette\Database\Connection $database)
{
$this->database = $database;
}
/**
* Performs an authentication
* @param array
* @return Nette\Security\Identity
* @throws Nette\Security\AuthenticationException
*/
public function authenticate(array $credentials)
{
list($username, $password) = $credentials;
//$row = $this->users->where('username', $username)->fetch();
$row = $this->database->table('users')->where('username', $username)->fetch();
if (!$row) {
throw new Nette\Security\AuthenticationException("Špatná kombinace uživatelského jména a hesla.", self::IDENTITY_NOT_FOUND);
}
echo $this->calculateHash($password, $username);
if ($row->password !== $this->calculateHash($password, $username) || $row->disabled==1) {
throw new Nette\Security\AuthenticationException("Špatná kombinace uživatelského jména a hesla.", self::INVALID_CREDENTIAL);
}
unset($row->password);
return new Nette\Security\Identity($row->id_user, "user", $row->toArray());
}
/**
*
* Gets username by his id.
*
* @param int $id id of user we want to know
* @return string username
*/
public static function getUsernameById($id)
{
return dibi::select('username')->from('users')->where('id_user=%i', $id)->fetchSingle();
}
/**
* Computes salted password hash.
* @param string password
* @return string hash salted by username
*/
public static function calculateHash($password, $username)
{
return md5($password . 'salt' . $username);
}
}
?>
- mistm
- Člen | 25
Pro jistotu jeste uvadim bootstrap.php
<?php
use Nette\Diagnostics\Debugger, Nette\Application\Routers\Route;
use Nette\Forms\Container;
// Load Nette Framework
$params['libsDir'] = __DIR__ . '/../libs';
require $params['libsDir'] . '/Nette/loader.php';
// Enable Nette Debugger for error visualisation & logging
Debugger::$logDirectory = __DIR__ . '/../log';
Debugger::$strictMode = TRUE;
Debugger::enable();
require $params['libsDir'] . '/dibi/dibi.php';
// Load configuration from config.neon file
/*$configurator = new Nette\Configurator;
$configurator->container->params += $params;
$configurator->container->params['tempDir'] = __DIR__ . '/../temp';
$container = $configurator->loadConfig(__DIR__ . '/config.neon');*/
$configurator = new Nette\Config\Configurator;
$configurator->setTempDirectory(__DIR__ . '/../temp');
$configurator->createRobotLoader()
->addDirectory(__DIR__)
->addDirectory($params['libsDir'])
->register();
$configurator->addParameters($params);
$configurator->addConfig(__DIR__ . '/config.neon');
$container = $configurator->createContainer();
dibi::connect( $container->params['database'] );
// Setup router
$router = $container->router;
$router[] = new Route('index.php', 'Sign:in', Route::ONE_WAY);
$router[] = new Route('', 'Sign:in');
$router[] = new Route('<presenter>/<action>[/<id>]', 'Sign:');
Container::extensionMethod('addDatePicker', function (Container $container, $name, $label = NULL) {
return $container[$name] = new JanTvrdik\Components\DatePicker($label);
});
\Nette\Diagnostics\Debugger::$bar->addPanel(new SessionPanel($container->session));
// Configure and run the application!
$application = $container->application;
//$application->catchExceptions = TRUE;
$application->errorPresenter = 'Error';
$application->run();
- mistm
- Člen | 25
Promin, ze jsem tak dlouho nereagoval. Nevsiml jsem si odpovedi.
V mem kodu se posledni vola: $this->getUser()->login($values->username, $values->password);
public function signInFormSubmitted($form)
{
try {
$values = $form->getValues();
$this->getUser()->login($values->username, $values->password);
$this->redirect('Hlidac:default');
} catch (NS\AuthenticationException $e) {
$form->addError($e->getMessage());
$this->redirect('Sign:in');
}
}
V call stacku pak dal vidim, ze to skonci na Nette/Security/User.php:177:
final public function getAuthenticator()
{
return $this->authenticator ?: $this->context->getByType('Nette\Security\IAuthenticator');
}
- mistm
- Člen | 25
vvoody napsal(a):
- definíciu služby authenticator v configu
services:
authenticator:
class: Authenticator( @database )
- obsah property public $classes vo vygenerovanom DIC
Doufam, ze se to vypise takto… volam print_r($this->getContext()->classes); tesne pred mym radkem, kde to pada.
Array ( [nette\object] => [nette\caching\storages\ijournal] => nette.cacheJournal [nette\caching\storages\filejournal] => nette.cacheJournal [nette\caching\istorage] => cacheStorage [nette\caching\storages\filestorage] => cacheStorage [nette\http\requestfactory] => nette.httpRequestFactory [nette\http\irequest] => httpRequest [nette\http\request] => httpRequest [nette\http\iresponse] => httpResponse [nette\http\response] => httpResponse [nette\http\context] => nette.httpContext [nette\http\session] => session [nette\security\iuserstorage] => nette.userStorage [nette\http\userstorage] => nette.userStorage [nette\security\user] => user [nette\application\application] => application [nette\application\ipresenterfactory] => nette.presenterFactory [nette\application\presenterfactory] => nette.presenterFactory [nette\arraylist] => router [traversable] => router [iteratoraggregate] => router [countable] => router [arrayaccess] => router [nette\application\irouter] => router [nette\application\routers\routelist] => router [nette\mail\imailer] => nette.mailer [nette\mail\sendmailmailer] => nette.mailer [nette\di\nestedaccessor] => nette.database [nette\freezableobject] => container [nette\ifreezable] => container [nette\di\icontainer] => container [nette\di\container] => container )
- celu metodu createServiceAuthenticator z vygenerovaného DIC ak tam existuje
Tady nevim presne oc me zadas. Nejsem na Nette zrovna specialista :-) Ve svem kodu zadnou metodu createServiceAuthenticator nemam. Pokud ji tam mam mit, tak tam muze byt problem.
- jiri.pudil
- Nette Blogger | 1029
Metodu createServiceAuthenticator hledej v temp/cache/_Nette.Configurator/*
- vvoody
- Člen | 910
Je to hodne divné, podla tej property classes to vyzerá tak akoby si mal prázdny config, respektíve tvoj config nebol predaný configuratoru. Chýbajú tam aj ďalšie služby ktoré máš v configu (PolozkyOpravy, Model)
Teraz pozerám na:
$configurator->addConfig(__DIR__ . '/config.neon');
nemáš ho náhodou v zložke?
$configurator->addConfig(__DIR__ . '/config/config.neon');
To by síce kričalo že ten __DIR__ . ‚/config.neon‘ neexistuje, ale možno aj existuje a je prázdny.
- mistm
- Člen | 25
Tak tedy createServiceAuthenticator jsem v _Nette.Configurator/cosi.php vubec nenasel.
config.neon mam primo v app. Do bootstrap.php jsem si zkusil pridat
echo __DIR__ . '/config.neon';
a dostal jsem D:\xampp\htdocs\HlidacObjednavek\app/config.neon – coz je presne cesta, kde je config.neon ulozen.
Nemusi byt v tom .neon presny odsazeni? Napr na radku za services: ma byt prave 1× tab (tzn nesmi byt 2x)? Nebo neni tam nejaky znak pro viceradkovy komentar (jakoze je moje konfigurace zakomentovana)? Ostatne .neon je vyse.
Editoval mistm (29. 1. 2013 3:05)
- mistm
- Člen | 25
Config to urcite nacita, protoze v tom _Nette.Configurator/cosi.php jsem nasel nasledujici kod, kde je mnou definovane currency a language.
public function __construct()
{
parent::__construct(array(
'appDir' => 'D:\\xampp\\htdocs\\HlidacObjednavek\\app',
'wwwDir' => 'D:\\xampp\\htdocs\\HlidacObjednavek\\document_root',
'debugMode' => TRUE,
'productionMode' => FALSE,
'environment' => 'development',
'consoleMode' => FALSE,
'container' => array(
'class' => 'SystemContainer',
'parent' => 'Nette\\DI\\Container',
),
'tempDir' => 'D:\\xampp\\htdocs\\HlidacObjednavek\\app/../temp',
'libsDir' => 'D:\\xampp\\htdocs\\HlidacObjednavek\\app/../libs',
'language' => 'cs',
'currency' => 'Kč',
'database' => array(
'driver' => 'mysql',
'host' => 'localhost',
'database' => 'databaze',
'username' => 'user',
'password' => 'pass',
'profiler' => TRUE,
'charset' => 'utf8',
),
));
}
Editoval mistm (29. 1. 2013 3:13)
- mistm
- Člen | 25
Zkusil jsem .neon prekopat podle .neonu v sanboxu a podle toho co pises. Chyba uz je jina:
Found sections 'database' in configuration, but corresponding extensions are missing.
Vzpominam si, ze jsem tuto hlasku uz videl pri prechodu na novou verzi. Hledal jsem na foru a vysel mi z toho ten config vys, ktery „fungoval“, protoze se tam ty veci nenacitaly :-) Cili byla chyba opravdu asi v nem. Jen nevim co ted s timto. Pouzivam dibi.
common:
php: # PHP configuration
date.timezone: Europe/Prague
# session.save_path: "%tempDir%/sessions"
# zlib.output_compression: yes
nette:
debugger:
strictMode: true
bar:
- @sessionPanel
session:
autoStart: smart
expiration: +5 days
services:
robotLoader:
run: true
database:
class: Nette\Database\Connection('mysql:host=localhost;dbname=databaze', 'user', 'pass')
model:
class: Model
arguments: [@database]
authenticator:
class: Authenticator( @database )
polozkyOpravy:
class: PolozkyOpravy
arguments: [@session]
sessionPanel:
class: SessionPanel
arguments:
- @application
- @session
factories:
parameters:
language: 'cs'
currency: 'Kč'
development < common:
database:
driver: mysql
host: localhost
database: databaze
username: user
password: pass
profiler: TRUE
charset: utf8
production < common:
database:
driver: mysql
host: localhost
database: databaze
username: user
password: pass
profiler: TRUE
charset: utf8
Zkusil jsem config jako je zde https://forum.nette.org/…di-container#… a dostal jsem tu samou hlasku.
- Tomas Jancik
- Člen | 103
parametry pro pripojeni k databazi zanor do sekce parameters
development < common:
parameters:
database:
driver: mysql
host: localhost
database: databaze
username: user
password: pass
profiler: TRUE
charset: utf8
production < common:
parameters:
database:
driver: mysql
host: localhost
database: databaze
username: user
password: pass
profiler: TRUE
charset: utf8
- Tomas Jancik
- Člen | 103
snazis se vytvorit service robotLoader, ale nespecifikujes odkud se ma vzit (ktera trida nebo tovarnicka)
jak uz tady psal @castamir, robotLoader bys v configu vubec nemusel definovat
- castamir
- Člen | 629
bud to napises ve zkracene notaci, nebo ve zdlouhave, rozhodne bych to nekombinoval
zdlouhavy zapis
authenticator:
class: Authenticator
arguments: [@database]
zkraceny
authenticator: Authenticator
zkraceny s explicitnim nastavenim parametru
authenticator: Authenticator ( @database )
Vyzkousej a dej vedet
Editoval castamir (29. 1. 2013 13:21)
- mistm
- Člen | 25
Zkusil jsem vsechny 3 varianty a porad to same. Pri zkracenem zapisu authenticator: Authenticator to hazi
Service 'authenticator': No service of type Nette\Database\Connection found. Make sure the type hint in Method Authenticator::__construct() is written correctly and service of this type is registered.
Ja v config.neon ale zadnou service Connection nemam.
- mistm
- Člen | 25
Upravil jsem tedy konstruktor na public function __construct(DibiConnection $database)
Pak jsem jeste zmenil z…
model:
class: Model
arguments: [@database]
sessionPanel:
class: SessionPanel
arguments:
- @application
- @session
… na …
model:
class: Model
arguments: [%database%]
sessionPanel:
class: SessionPanel
arguments:
- @session
Ted mi ale rve \libs\dibi\libs\DibiObject.php
Call to undefined method DibiConnection::table().
Chapu to dobre, ze injektuju DibiConnection necemu, co ocekava nejakej interface Connection, kterej ma mit metodu table()?
Editoval mistm (29. 1. 2013 18:23)
- castamir
- Člen | 629
už se blížíme. Zkusím sem psotnout jednoduchý config, který jsem si před chvilkou vyzkoušel. Snad se ti to podle toho podaří opravit.
common:
parameters:
php:
date.timezone: Europe/Prague
nette:
application:
errorPresenter: Front:Error
session:
expiration: 14 days
services:
authenticator: Authenticator ( @dibi.connection )
users: Users ( @dibi.connection )
factories:
dibi:
driver: %database.driver%
charset: utf8
lazy: true
host: %database.host%
username: %database.user%
password: %database.password%
database: %database.dbname%
profiler: true
result:
detectTypes: true
production < common:
development < common:
parameters:
database:
driver: mysql
host: localhost
dbname: mydbname
user: username
password:
- Badaboom
- Člen | 33
DibiConnection
nemá metodu table()
. Ty ji ale používáš. Ten Authenticator výše
je hybrid, který používá Dibi i Nette\Database.
Např. tohle je zápis pro Nette\Database:
$row = $this->database->table('users')->where('username', $username)->fetch();
Přepiš to na Dibi.
Editoval Badaboom (29. 1. 2013 18:32)