Create Login functionality in Expressive 3
Zend Expressive 3 is not released yet released, and expressive session related components are in active development ready to use. However, we already can give them a try.
Use case
For example, we need simple login functionalities:
- Login Form
- Authentication process, read from DB
- Save authenticated value to Session
Setup
First, we can install the Zend Expressive 3 skeleton with the following command:
$ composer create-project "zendframework/zend-expressive-skeleton:^3.0.0" expressive3
Important Notes:
When prompted with service container requirement, choose zend-servicemanager
When prompted with template engine requirement, choose zend-view
There are components that can be installed via command:
$ cd expressive3 $ composer require \ zendframework/zend-form:^2.11 \ zendframework/zend-i18n:^2.7 \ zendframework/zend-expressive-authentication:^1.0 \ zendframework/zend-expressive-authentication-session:^1.0 \ zendframework/zend-expressive-session:^1.0 \ zendframework/zend-expressive-session-ext:^1.0
After above components installed, ensure that your config/config.php
injected with ConfigProvider
like below:
<?php // config/config.php $aggregator = new ConfigAggregator([ // ... form requirements \Zend\I18n\ConfigProvider::class, \Zend\Form\ConfigProvider::class, \Zend\InputFilter\ConfigProvider::class, \Zend\Filter\ConfigProvider::class, \Zend\Hydrator\ConfigProvider::class, // ... // ... auth requirements \Zend\Expressive\Authentication\ConfigProvider::class, \Zend\Expressive\Authentication\Session\ConfigProvider::class, \Zend\Expressive\Session\ConfigProvider::class, \Zend\Expressive\Session\Ext\ConfigProvider::class, // ... ];
we can first setup database data, in this case, I tried with Postgresql:
$ createdb -Udeveloper expressive Password: $ psql -Udeveloper expressive Password for user developer: psql (10.1) Type "help" for help. expressive=# CREATE TABLE users(username character varying(255) PRIMARY KEY NOT NULL, password text NOT NULL); CREATE TABLE expressive=# CREATE EXTENSION pgcrypto; CREATE EXTENSION expressive=# INSERT INTO users(username, password) VALUES('samsonasik', crypt('123456', gen_salt('bf'))); INSERT 0 1
Above, I create database named “expressive”, create table named “users” with username and password field, insert sample data with pgcrypto extension for create hashed password of 123456 using blowfish.
Now, we can setup the authentication configuration at config/autoload/local.php
as follows:
<?php // config/autoload/local.php return [ 'authentication' => [ 'pdo' => [ 'dsn' => 'pgsql:host=localhost;port=5432;dbname=expressive;user=developer;password=xxxxx', 'table' => 'users', 'field' => [ 'identity' => 'username', 'password' => 'password', ], ], 'username' => 'username', 'password' => 'password', 'redirect' => '/login', ], ];
Then, we can map Zend\Expressive\Authentication\UserRepositoryInterface::class
to Zend\Expressive\Authentication\UserRepository\PdoDatabase::class
under alias
and register Zend\Expressive\Authentication\AuthenticationInterface::class
under factories
config at config/autoload/dependencies.global.php
:
<?php // config/autoload/dependencies.global.php return [ 'dependencies' => [ 'aliases' => [ // ... Zend\Expressive\Authentication\UserRepositoryInterface::class => Zend\Expressive\Authentication\UserRepository\PdoDatabase::class ], 'factories' => [ // ... Zend\Expressive\Authentication\AuthenticationInterface::class => Zend\Expressive\Authentication\Session\PhpSessionFactory::class, ], // ... ], ];
For Session operations, we need Zend\Expressive\Session\SessionMiddleware
middleware before routing middleware, so, in config/pipeline.php
, we call pipe on it before $app->pipe(RouteMiddleware::class);:
// ... $app->pipe(\Zend\Expressive\Session\SessionMiddleware::class); // Register the routing middleware in the middleware pipeline $app->pipe(RouteMiddleware::class); // ...
as example: we want to redirect non-logged user to /login
page, eg: at home page (/), we can register “home” routes config:
<?php // config/routes.php $app->route('/', [ \Zend\Expressive\Authentication\AuthenticationMiddleware::class, App\Handler\HomePageHandler::class, ], ['GET'], 'home');
Now run the php -S command:
$ php -S localhost:8080 -t public
When access ‘/’ page via localhost:8080, we should be redirected to /login
page which currently a 404 page, nice!
Login Page
First, we create a LoginForm
with username
and password
field like the following:
<?php // src/App/Form/LoginForm.php declare(strict_types=1); namespace App\Form; use Zend\Form\Element\Password; use Zend\Form\Element\Text; use Zend\Form\Form; use Zend\InputFilter\InputFilterProviderInterface; class LoginForm extends Form implements InputFilterProviderInterface { public function __construct() { parent::__construct('login-form'); } public function init() { $this->add([ 'type' => Text::class, 'name' => 'username', 'options' => [ 'label' => 'Username', ], ]); $this->add([ 'type' => Password::class, 'name' => 'password', 'options' => [ 'label' => 'Password', ], ]); $this->add([ 'name' => 'Login', 'type' => 'submit', 'attributes' => [ 'value' => 'Login', ], ]); } public function getInputFilterSpecification() { return [ [ 'name' => 'username', 'required' => true, 'filters' => [ ['name' => 'StripTags'], ['name' => 'StringTrim'], ], ], [ 'name' => 'password', 'required' => true, 'filters' => [ ['name' => 'StripTags'], ['name' => 'StringTrim'], ], ], ]; } }
We then can create a login page handler with inject it with login form with the following factory:
<?php // src/App/Handler/LoginPageFactory.php declare(strict_types=1); namespace App\Handler; use App\Form\LoginForm; use Psr\Http\Server\MiddlewareInterface; use Psr\Container\ContainerInterface; use Zend\Expressive\Template\TemplateRendererInterface; use Zend\Form\FormElementManager; class LoginPageFactory { public function __invoke(ContainerInterface $container) : MiddlewareInterface { $template = $container->get(TemplateRendererInterface::class); $loginForm = $container->get(FormElementManager::class) ->get(LoginForm::class); return new LoginPageHandler($template, $loginForm); } }
The LoginPageHandler
itself can be initialized with :
<?php // src/App/Handler/LoginPageHandler.php declare(strict_types=1); namespace App\Handler; use App\Form\LoginForm; use Psr\Http\Server\MiddlewareInterface; use Psr\Http\Server\RequestHandlerInterface; use Psr\Http\Message\ResponseInterface; use Psr\Http\Message\ServerRequestInterface; use Zend\Diactoros\Response\HtmlResponse; use Zend\Diactoros\Response\RedirectResponse; use Zend\Expressive\Authentication\UserInterface; use Zend\Expressive\Session\SessionMiddleware; use Zend\Expressive\Template\TemplateRendererInterface; class LoginPageHandler implements MiddlewareInterface { private $template; private $loginForm; public function __construct( TemplateRendererInterface $template, LoginForm $loginForm ) { $this->template = $template; $this->loginForm = $loginForm; } public function process(ServerRequestInterface $request, RequestHandlerInterface $handler) : ResponseInterface { $session = $request->getAttribute(SessionMiddleware::SESSION_ATTRIBUTE); if ($session->has(UserInterface::class)) { return new RedirectResponse('/'); } $error = ''; // handle authentication here Next return new HtmlResponse( $this->template->render('app::login-page', [ 'form' => $this->loginForm, 'error' => $error, ]) ); } }
Above, we redirect to ‘/’ page when there is a session data as it already authenticated check. We are going to add authentication process next.
The Login form can be as simple as the following:
<?php // templates/app/login-page.phtml echo $error; $form->prepare(); echo $this->form($form);
We can register the LoginPageHandler
at App\ConfigProvider::getDependencies()
config:
<?php // src/App/ConfigProvider.php class ConfigProvider { public function getDependencies() : array { return [ 'invokables' => [ /**/ ], 'factories' => [ // ... Handler\LoginPageHandler::class => Handler\LoginPageFactory::class, ], ]; } }
The routing can be registered as follows with add \Zend\Expressive\Authentication\AuthenticationMiddleware::class
for next middleware:
// config/routes.php // ... $app->route('/login', [ App\Handler\LoginPageHandler::class, // for authentication next handling \Zend\Expressive\Authentication\AuthenticationMiddleware::class, ], ['GET', 'POST'],'login');
Above, we allow ‘GET’ and ‘POST’ in same ‘/login’ page.
Authentication process
Time for authentication process, we utilize Zend\Expressive\Authentication\AuthenticationMiddleware
class that registered at the last entry at the /login
route, we can accomodate it after check of form is valid
<?php // src/App/Handler/LoginPageHandler.php class LoginPageHandler implements MiddlewareInterface { // ... public function __construct( TemplateRendererInterface $template, LoginForm $loginForm) { /* */ } public function process( ServerRequestInterface $request, RequestHandlerInterface $handler ) : ResponseInterface { // ....... $error = ''; if ($request->getMethod() === 'POST') { $this->loginForm->setData($request->getParsedBody()); if ($this->loginForm->isValid()) { $response = $handler->handle($request); if ($response->getStatusCode() !== 302) { return new RedirectResponse('/'); } $error = 'Login Failure, please try again'; } } // ... return new HtmlResponse( $this->template->render('app::login-page', [ 'form' => $this->loginForm, 'error' => $error, ]) ); }
We call handle($request)
for next Zend\Expressive\Authentication\AuthenticationMiddleware
with:
$response = $handler->handle($request); if ($response->getStatusCode() !== 302) { return new RedirectResponse('/'); }
When status code is not 301 302, it authenticated and session filled, we can then redirect to page that need to be authenticated to be access. Failure authentication default behaviour has 301 302 status code which we can set config “redirect” in “authentication” config, on above code, I just want to show it in the login form that the login failure, so I set the $error variable value to “Login Failure, please try again”, so when login failure, it will got the error like the following:
That’s it ;).
How about logout ? We can use clear()
method from SessionMiddleware::SESSION_ATTRIBUTE
attribute like the following:
use Zend\Expressive\Authentication\UserInterface; use Zend\Expressive\Session\SessionMiddleware; class LogoutPageHandler implements RequestHandlerInterface { public function handle(ServerRequestInterface $request) : ResponseInterface { $session = $request->getAttribute(SessionMiddleware::SESSION_ATTRIBUTE); if ($session->has(UserInterface::class)) { $session->clear(); } // ... } }
How about authorization part? You can read my next post about create authorization functionality in zend expressive 3
Thanks for an interesting post. Being not even a novice with Expressive, I’m not yet familiar with the wiring, so I ask: in the snippet that comes after “We call handle($request) for next Zend\Expressive\Authentication\AuthenticationMiddleware with:”, what file would that live in?
the next is a `\Zend\Expressive\Authentication\AuthenticationMiddleware` class which it passed at “login” route at last entry config value, the `\Zend\Expressive\Authentication\ConfigProvider::class` that registered at `config/config.php` handle its service registration.
[…] yesterday, I already posted about Authentication part in “Create Login functionality in Expressive 3” post, so, it’s time for authorization part. If you didn’t read that, please read […]
[…] you followed my post about authentication and authorization posts with Expressive 3, this time, I write another session related post for […]
[…] you already followed my 4 previous expressive posts, all requirements already […]
I get the following error: Service with name “Zend\Expressive\Authentication\AuthenticationInterface” could not be created. Reason: The redirect configuration is missing for authentication.
I retried with run “composer update” to get latest dependencies, and it just works! You probably missing something in the steps, please follow slowly.
Of course you have to provide the key ‘redirect’ in the [‘config’][‘authentication’] configuration file as described in Zend\Expressive\Authentication\Session\PhpSessionFactory (where the AuthenticationInterface is mapped in)
The key is used in case of unauthorizedResponse
Hello? Have you had the project code, folder or structure? I have the following error: “Service with name “App\Handler\LoginPageHandler” could not be created. Reason: A plugin by the name “App\Form\LoginForm” was not found in the plugin manager Zend\Form\FormElementManager\FormElementManagerV3Polyfill”
as in setup described in the post, you need to install `zend-form` and ensure `\Zend\Form\ConfigProvider::class` registered in the ConfigAggregator. By that, the `App\Form\LoginForm` will got auto discover via FormElementManager.
Am having the same issue and have read through a couple times. Could you explain this?
My zend expressive skeloton has src/App/src as the main folder
do you use `zend-servicemanager` and `zend-view` ? If you’re using both components for container and template engine, that should works.
// src/App/Form/LoginForm.php must be // src/App/src/Form/LoginForm.php
that depends on what expressive project structure you have, both can work as far as the composer pointed to the correct directory for `App` namespace.
I am getting the same error. And I have zend-form and zend-view installed by composer. Even ran composer update but still the error persists. \Zend\Form\ConfigProvider::class is also registered in the config aggregator.
It seems this problem has to do with https://github.com/zendframework/zend-servicemanager/issues/165.
Using FormElementManagerV3Polyfill::class instead also does not help.
Do you have any ideas how to fix this?
I retried the repository https://github.com/samsonasik/expressive3-example-auth-with-prg and that just work. Please follow the readme.
Missing ‘redirect’ => ‘/login’ in [‘config’][‘authentication’] config.
Thank you. I’ve updated the post with latest compatible components settings.
Thanks. Very informative and professional
I’m getting this error:
Uncaught Zend\ConfigAggregator\InvalidConfigProviderException: Cannot read config from Zend\Expressive\Sesssion\ConfigProvider – class cannot be loaded.
I created repository for auth in expressive 3, you can follow the readme at https://github.com/samsonasik/expressive3-example-auth-with-prg
Previous errors gone. Cannot find any difference between my code and yours, but still getting the below error:
`Too few arguments to function App\Handler\LoginPageHandler::__construct(), 0 passed in /path/to/myproject/vendor/zendframework/zend-servicemanager/src/Factory/InvokableFactory.php on line 30 and exactly 2 expected`
The error already gave you the hint, you’re using InvokableFactory, while it needs a real factory class to build the LoginPageHandler instance and pass 2 parameters (if you are using based of tutorial). Please follow tutorial slowly, and do effort.
I have the following error:
Unable to resolve service “Zend\Expressive\Template\TemplateRendererInterface” to a factory; are you certain you provided it during configuration?
Can you help me?
—
Estou com o seguinte erro:
Unable to resolve service “Zend\Expressive\Template\TemplateRendererInterface” to a factory; are you certain you provided it during configuration?
Podem me ajudar?
When install zend-expressive-skeleton in the first place with default application type, you can choose “zend-view” when asked for template engine to be used:
It worked! Thank you.
Unable to resolve service “Zend\Expressive\Application” to a factory;
Can you help me?
Are you sure you follow the steps correctly. Anyway, I created a working example repository for it at https://github.com/samsonasik/expressive3-example-auth-with-prg
The error is gone, do you have this tutorial also on github?
if you follow this post step by step correctly, you should have a working example. In github, the addition is for flash, csrf, prg.
Now I have the following errror: ‘Too few arguments to function App\Handler\HomePageHandler::__construct(), 0 passed in /var/www/fyn.nl/playground/blog/vendor/zendframework/zend-expressive/src/MiddlewareContainer.php on line 64 and exactly 3 expected’
Can you help?
it seems you missing install zend-view template engine, look on previous comment https://samsonasik.wordpress.com/2018/01/12/create-login-functionality-in-expressive-3/#comment-36091
How can I install zend-view template engine?
in very first install of the skeleton, you need to:
1. choose service container, choose zend servicemanager
2. choose template engine, choose zend view
You were right indeed I had not downloaded a template engine. but I have another error: Unable to render template “error::error”;
are you sure you install non-minimal nstallation on the first place ( please choose modular or flat instead )
are you sure you install non-minimal installation on the first place ( please choose modular or flat instead )
Reply: Probably i did it wrong but how can I change it?
you can check structure at https://github.com/samsonasik/expressive3-example-auth-with-prg to compare.
it looks the same, you may have another idea o fix this?
do you run php development server with command:
php -S localhost:8080 -t public
if no, please try and open with browser http://localhost:8080 . otherwise, i have no idea, the error shows that you don’t have error.phtml file.
Hi I have a question about LoginPageHandler. The first LoginPageHandler file I did exactly what you did but at the Authentication process you didn’t type some lines. My question is do I have to type those lines or not.
Yes, you need to type that, “// …….” lines mean you need to apply after previous code.
‘Service with name “Zend\Expressive\Authentication\AuthenticationMiddleware” could not be created. Reason: AuthenticationInterface service is missing’
Can you help please?
please check step on defining `Zend\Expressive\Authentication\AuthenticationInterface::class` in factory in the post at config/autoload/dependencies.global.php.
When I log in, I get this error: Cannot fetch middleware service “AuthenticationMiddleware”; service not registered, or does not resolve to an autoloadable class name.
Can you help me?
please check if ` \Zend\Expressive\Authentication\ConfigProvider::class,` registered in `config/config.php`, follow the post step by step.
\Zend\Expressive\Authentication\ConfigProvider::class is just in config/config.php. Do you have another idea?
that’s probably cache issue, please ensure there is no cache files in data/cache directory. Also, run the composer development-enable command. Anyway, I created sample repo at https://github.com/samsonasik/expressive3-example-auth-with-prg
There is no cache file in data/cache and i did run the composer development-enable command.
But it still doesn’t work and I get the same error. I also looked at your github page but that seems almost the same.
So any other idea?
Did you try clone and run my repo on github with follow the steps in the readme file ?
No actually I was doing the tutorial above but this tutorial should actually work right?
I have still the same error. I can share my github that you can see what I might be doing wrong.
Yes, that should work and I tested it before post it. See comment https://samsonasik.wordpress.com/2018/01/12/create-login-functionality-in-expressive-3/#comment-36093 which works.
You can check my github repo which worked out of the box at my side and compare yourself if there is something missed.
I solved the previous error thanks to your githubpage. But now I have this error: Service with name “Zend\Expressive\Authentication\AuthenticationInterface” could not be created. Reason: The redirect configuration is missing for authentication.
In config/local.php.dist I just have a redirect like this: ‘authentication’ => [ //… ‘redirect’ => ‘/login’, ],
Do you have any idea to solve this error.
I’ve added redirect config at config/autoload/local.php.dist https://github.com/samsonasik/expressive3-example-auth-with-prg/commit/150adda961aff907a05966ed77736ced49d0f088, you can pull and re-copy it to config/autoload/local.php
How should you do the sql part for mysql (https://localhost/phpmyadmin)? how should you do the sql part for localhost / phpmyadmin? I’m stuck in the sql part, could you explain it for mysql?
well, it seems you need to learn mysql first. hashing using blowfish can utilize php password_hash function, or you can generate first online, eg http://www.passwordtool.hu/blowfish-password-hash-generator
I know the basics of Mysql but your line (NSERT INTO users(username, password) VALUES(‘samsonasik’, crypt(‘123456’, gen_salt(‘bf’)));) can’t on mysql.(phpmyadmin)
On the internet I only see examples for PHP itself. And I don’t know where to put those queries in send expressive.
you can get generated the bcrypt value first via php or online first, then apply the value to sql insert:
INSERT INTO users(username, password) VALUES(‘samsonasik’, ‘the generated bcrypt value for 123456’);
Service with name “Zend\Expressive\Authentication\UserRepository\PdoDatabase” could not be created. Reason: SQLSTATE[HY000] [1045] Access denied for user ”@’localhost’ (using password: NO)
Can you help?
that’s db configuration issue, check your db config
I get these errors:
A comma or a closing bracket was expected. (near “varying” at position 38)
Unexpected beginning of statement. (near “255” at position 46)
Unrecognized statement type. (near “PRIMARY KEY” at position 51).
When I put this line in sql: CREATE TABLE users(username character varying(255) PRIMARY KEY NOT NULL, password text NOT NULL);
use varchar(255) instead of character varying(255) for mysql.
wanneer ik inlog met het correcte gebruikersnaam en wachtwoord krijg ik de $error: Login Failure, please try again.
Do you have any idea?
please do effort, check the error slowly!
I would like to call the PDO, how can I do that?
it depends on what do you want to achieve with the PDO instance. If you want to override the `PdoDatabase::authenticate()`, you may extends the `Zend\Expressive\Authentication\UserRepository\PdoDatabase` and make service delegator for it.
how should I create a service delegator?
you can read about service delegator here: https://docs.zendframework.com/zend-servicemanager/delegators/
This is example of custom Authentication for Oauth2 in apigility app with service delegators https://samsonasik.wordpress.com/2016/08/21/apigility-create-custom-authentication-for-oauth2-with-service-delegators/
the concept is same.
I don’t want to waste any more code by using this line:
$pdo = new PDO(“mysql:host=$servername;port=3306;dbname=test;”, $username, $password);
While I’ve already entered it at local.php.
I want to use it with another page handler, so I am not talking about Loginpagehandler now, that works fine :).
for db operation that unrelated to this authentication purpose, I suggest you just need to use zendframework/db or laminas/db if you already migrated. see https://docs.laminas.dev/tutorials/db-adapter/
Can you make a tutorial about zend-db?
I created a cheat sheet about zend-db at https://samsonasik.wordpress.com/2013/01/15/zend-framework-2-cheat-sheet-zenddb/
wrong:
‘authentication’ => [
‘pdo’ => [
‘dsn’ => ‘pgsql:host=localhost;port=5432;dbname=expressive;user=developer;password=xxxxx’,
‘table’ => ‘users’,
‘field’ => [
‘identity’ => ‘username’,
‘password’ => ‘password’,
],
It should be this:
‘authentication’ => [
‘pdo’ => [
‘dsn’ => ‘pgsql:host=localhost;dbname=expressive’,
‘username’ => ‘developer’,
‘password’ => ‘xxxxx’,
‘table’ => ‘users’,
‘field’ => [
‘identity’ => ‘username’,
‘password’ => ‘password’,
],
both are correct, you can choose what you like.
I have still the same error, With your code I get this error: (local.php)
Service with name “Zend\Expressive\Authentication\UserRepository\PdoDatabase” could not be created. Reason: SQLSTATE[HY000] [1045] Access denied for user ”@’localhost’ (using password: NO)
But with my code I don’t get an error but nothing happens when I click on login button.
Only what happens is that the error appears.(Login Failure, please try again)
So any idea to help, let me know please.
compare your database setting and your local.php setting, eg with my config, it is using postgresql with user=developer and password=xxxxx and db name=expressive.
If I put this in my code then I get the output correctly.
try
{
$pdo = new PDO(“mysql:host=$servername;port=3306;dbname=test;”, $username, $password);
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$pdotest = “Connected successfully”;
}
catch(PDOException $e)
{
$pdotest = “Connection failed: ” . $e->getMessage();
}
That is exactly the same line that is in local.php.
I assume you use empty password for MySQL user=root, you can use the following dns string:
In Db, you can insert to users table with dbname=expressive:
above, I inserted username=samsonasik, password = bcrypted of 123456 into users table.
I even created a whole new project and it doesn’t work yet. Did you also try it yourself with a new project. If
If I don’t put the username and password in the dsn then I don’t get an error but I still can’t log in. so I haven’t got anything further. 😦
Maybe it is more convenient that we do this via e-mail because there are still a number of messages?
I tried myself on mysql and that works. As developer, please do effort. more effort.
If I don’t hash the password, does it not work anyway?
I do not hash the password because I want to see if it works, then of course I will.
it uses zend-expressive-authentication middleware that uses password_verify function, you need to pass bcrypted data in the database. see https://github.com/zendframework/zend-expressive-authentication/blob/master/src/UserRepository/PdoDatabase.php#L85
Yes it works thank you. it only works if you hashed the password. But now I have the following problem. When I am logged in I will be redirected to the homepage but if I go to /login again I will have to log in again. Do you know why this line is set to false?
if ($ session-> has (Userinterface :: class))
I assume you have missed use statement of:
in LoginPageHandler.
You can debug that session is there with $_SESSION. Please read phpmanual https://www.php.net/manual/en/function.session-start.php and learn about how to debug php app https://stackify.com/php-debugging-guide/ yourself.
I have the same issue, I can log in and the output ($session->has(UserInterface::class) is true.
But when I am on a other page then is it false.
It’s weird because I never destroyed the session.
Login page require `session->has(UserInterface::class)` check to be true, while other pages requre `session->has(UserInterface::class)` to be false as it will redirect to login page when it not login yet, eg:
in LoginPageHandler:
in HomePageHandler:
or just add the `AuthenticationMiddleware` before the HomePageHandler like the blog post:
I updated repository for its example at https://github.com/samsonasik/expressive3-example-auth-with-prg that already uses laminas components. you can follow the readme.
If the issue persist, it may related with your php ini setting, eg: session save path, etc. you can debug it.
Thank you, I did have an echo somewhere.
With your code I get this error:
Service with name “Zend\Expressive\Authentication\UserRepository\PdoDatabase” could not be created. Reason: SQLSTATE[HY000] [1045] Access denied for user ”@’localhost’ (using password: NO)
But with my code i don’t get an error.
that’s your db config issue, check your local db config.
If I use your lines then i get this error: Unable to emit response; headers already sent
it seems you have whitespace in the first line of files or echoed content somewhere in the middleware/handler, check again, slowly
I don’t see anything strange, this is my LoginPageHandler maybe you see something wrong.
class LoginPageHandler implements MiddlewareInterface
{
private $template;
private $loginForm;
public function __construct(
TemplateRendererInterface $template,
LoginForm $loginForm
){
$this->template = $template;
$this->loginForm = $loginForm;
}
public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
{
$session = $request->getAttribute(SessionMiddleware::SESSION_ATTRIBUTE);
if ($session->has(UserInterface::class)) {
return new RedirectResponse(‘/blog2/public/’);
}
$error = ”;
if ($request->getMethod() === ‘POST’)
{
$this->loginForm->setData($request->getParsedBody());
if ($this->loginForm->isValid())
{
$response = $handler->handle($request);
// var_dump($response->getStatusCode());
// die;
if ($response->getStatusCode() !== 302)
{
return new RedirectResponse(‘/blog2/public/’);
}
$error = ‘Login Failure, please try again’;
}
}
return new HtmlResponse(
$this->template->render(‘app::login-page’, [
‘form’ => $this->loginForm,
‘error’ => $error,
])
);
}
}
you can use php-cs-fixer to detect / fix whitespace https://github.com/FriendsOfPHP/PHP-CS-Fixer
but if you look to my code, do you see something that is not right?
it is hard to check whitespace in blog post comme t, you can check yourself.
should it be in this order?
$app->route(‘/’, [
\Zend\Expressive\Authentication\AuthenticationMiddleware::class, App\Handler\HomePageHandler::class ], [‘GET’], ‘home’);
(Now I can’t go to the homepage)
Because if I do it like this below then I can just go to the homepage:
$app->route(‘/blog2/public/’, [App\Handler\HomePageHandler::class, AuthenticationMiddleware::class, ], [‘GET’], ‘home’);
that’s depend on your requirement.
zend expressive Method Zend\View\Helper\HeadTitle::__toString() must not throw an exception, caught Zend\I18n\Exception\ExtensionNotLoadedException: Zend\I18n\Translator component requires the intl PHP extension
Can you help?
based on the error, you need to install intl php extension
Hi, I want to send a variable (string) with the return new RedirectResponse function.
But I don’t know how to do that.
I have seen at your githubpage you use flash messenger.
But are there any other ways?
you can bring value to other pages by GET request parameter, eg: ?message=hello and you can get query parameter based on it
So this line of code ( if ($session->has(UserInterface::class)) ) can I compare with a login check right?
For check “is login”, you can check with that, for getting data, you can get with:
More on that on authorization part at authorization post https://samsonasik.wordpress.com/2018/01/13/create-authorization-functionality-in-expressive-3/
How can I check if the username or password is correct / incorrect?
it is already there after form->isValid() check, it utilize AuthenticationMiddleware which check response status code, if response code !=302, the combination of username and password correct.
okay but there nothing happens when I enter the correct username and password.
I checked your tutorial and githubpage and it looks the same.
Do you know what I can do to fix this?
ensure that you have bcrypted password in users table, you can check first with password_verify function
I did not have my password hashed to be sure.
Hi, I have a question about the LoginPageFactory.php. PHPstorm says that FormElementMangager::class an undefined class is. I don’t get any error but I was wondering if it’s okay.
that’s fine as that is a service name, not a real class name
thank you, phpstorm would probably mean it well 😀
When I log in this line ( var_dump($response->getStatusCode()) die; ) get this output: int(404).
Is that supposed to be?
that’s weird, you probably missing something. I tried many times and it just working. You may need to try clone repository to your dev maching:
https://github.com/samsonasik/expressive3-example-auth-with-prg
Follow the readme.
I actually want to use this tutorial.
Is it also on github?
And it is laminas, i’m not familiar with that.
the one at github was using expressive, and migrated to laminas ( mostly namespace update ), the concept and flow actually same, just with already updated with csrf, flash, prg
it seems you’re using subdirectory for the app, you can read the documentation if you use subdirectory https://docs.zendframework.com/zend-expressive/v3/cookbook/using-a-base-path/