Giter Club home page Giter Club logo

mezzio-authentication-with-authorization's Introduction

Mezzio 3 with authentication with authorization

ci build pgsql ci build mysql Code Coverage Downloads

Introduction

A Mezzio 3 Skeleton Application with Authentication and Authorization Example.

Features

  • Authentication secured with csrf
  • Authentication using prg for usability
  • Authentication with remember me functionality
  • Authentication notification with Session Flash
  • Authorization with ACL
  • isGranted check in the Layout
  • getRole check in the Layout

Install

$ composer create-project samsonasik/mezzio-authentication-with-authorization -sdev
$ cd mezzio-authentication-with-authorization
$ cp config/autoload/local.php.dist config/autoload/local.php

Configuration

Configure your config/autoload/local.php with your local DB config with username and password field. There are examples of dsn for both PostgreSQL and MySQL that you can modify.

For PostgreSQL

The following commands are example if you are using PostgreSQL (assumption using user "postgres" and create db named "mezzio"), you can create users table with insert username and bcrypt hashed password with pgcrypto extension into users table:

$ createdb -Upostgres mezzio
Password:

$ psql -Upostgres mezzio
Password for user postgres:

psql (12.1)
Type "help" for help.

mezzio=# CREATE TABLE users(username character varying(255) PRIMARY KEY NOT NULL, password text NOT NULL, role character varying(255) NOT NULL DEFAULT 'user');
CREATE TABLE

mezzio=# CREATE EXTENSION pgcrypto;
CREATE EXTENSION

mezzio=# INSERT INTO users(username, password, role) VALUES('samsonasik', crypt('123456', gen_salt('bf')), 'user');
INSERT 0 1

mezzio=# INSERT INTO users(username, password, role) VALUES('admin', crypt('123456', gen_salt('bf')), 'admin');
INSERT 0 1

and you will get the following data:

user data

For MySQL

The following commands are example if you are using MySQL (assumption using user "root" and create db named "mezzio"), you can create users table with insert username and bcrypt hashed password:

$ mysql -u root -p -e 'create database mezzio'
Enter password:

$ mysql -u root
Enter password:

mysql> use mezzio
Database changed

mysql> CREATE TABLE users(username varchar(255) PRIMARY KEY NOT NULL, password text NOT NULL, role varchar(255) NOT NULL DEFAULT 'user');
Query OK, 0 rows affected (0.01 sec)

mezzio=# INSERT INTO users(username, password, role) VALUES('samsonasik','$2a$06$Nt2zePoCfApfBGrfZbHZIudIwZpCNqorTjbKNZtPoLCVic8goZDsi', 'user');
Query OK, 1 row affected (0.01 sec)

mezzio=# INSERT INTO users(username, password, role) VALUES('admin', '$2a$06$Y2TtankzyiK/OF1yZA4GsOJBhuoP7o99XbfufEeJ0OOJwjUcPB9LO', 'admin');
Query OK, 1 row affected (0.01 sec)

and you will get the following data:

user data

The Authorization Config

The authorization configuration saved at config/autoload/global.php as ACL:

<?php

// config/autoload/global.php

declare(strict_types=1);

return [
    // ...
    'mezzio-authorization-acl' => [
        'roles'     => [
            'guest' => [],
            'user'  => ['guest'],
            'admin' => ['user'],
        ],
        'resources' => [
            'api.ping.view',
            'home.view',
            'admin.view',
            'login.form',
            'logout.access',
        ],
        'allow'     => [
            'guest' => [
                'login.form',
                'api.ping.view',
            ],
            'user'  => [
                'logout.access',
                'home.view',
            ],
            'admin' => [
                'admin.view',
            ],
        ],
    ],
    // ...
];

Running

  1. Clear browser cache
  2. Run the php -S command:
$ php -S localhost:8080 -t public
  1. Open browser: http://localhost:8080

  2. Login with username : samsonasik, password: 123456 OR username : admin, password : 123456. If you're a logged in user with "user" role, and open /admin page, it will show like the following (403 Forbidden), eg: see in Firefox developer tools under "Network" monitor:

authorized-user-cannot-access-admin-page

Test

Tests are located under test directory, you can run test with composer command:

$ composer test

mezzio-authentication-with-authorization's People

Contributors

samsonasik avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

mezzio-authentication-with-authorization's Issues

Adding new user & role using MySQL

Hello

I am using MySQL for password and user storage. Could you please tell me how to create new passwords using MySQL when I have a new username and role in mind? I don't see a clear way towards doing so, and looking through code so far has me confused. Thanks!

CSRF issue

The CSRF is giving me an issue on mac os x, php 7.4.

"The form submitted did not originate from the expected site"

As far as I can tell, it is a problem with the session and how the csrf is stored. Somehow it looks as if it is recalculated after submitting.

How to incorporate it in the ongoing project?

From what I see, the only option there is to use it from the scratch. Can we not have the option of adding it in the ongoing project, like quite a few other packages?

Also, it is lacking the schema.sql which will be good to have.

How can I use this app for multiple granular in-view authorization queries?

Question - it seems that I can use authorization on a per-view-template level.

However, I have a use case to evaluate authorization on a more granular level.
For example, I have a module called Quote and in that module I have a quote view that shows a listing of sales items without their prices for customer view, but I want to show pricing for a sales person viewing the same quote view.

And so I am looking for a model where I can use something like this:

if ("logged in user" has permission to "view sales line item pricing")
    echo $price;
else
    echo "";

Where I can have multiple such statements on a single view.
It is not immediately clear if I can modify the app to use it in such a granular way.

Can I use mezzio-authentication-with-authorization for my use case? If so, how?
If I wanted to write a lot of such statements, how can I use (modify) this app?
Thanks!

Is there a way to use native ACL inside templates?

I want to use native ACL inside templates.

For example, inside a view template, something like:

$auth->isAllowed($role, $resource));
$this->isAllowed($role, $resource));

Is there an easy way to modify this app to do so? How?

Is this package compatible with composer v2? Doesn't seem like.

I've tried to install this package but this is what I got.

$ composer create-project samsonasik/mezzio-authentication-with-authorization -sdev
Creating a "samsonasik/mezzio-authentication-with-authorization" project at "./mezzio-authentication-with-authorization"
Installing samsonasik/mezzio-authentication-with-authorization (dev-master dcf300d89fa38248a21ca96266d50a847653e91e)
  - Syncing samsonasik/mezzio-authentication-with-authorization (dev-master dcf300d) into cache
  - Installing samsonasik/mezzio-authentication-with-authorization (dev-master dcf300d): Cloning dcf300d89f from cache
Created project in D:\laminas\mezzio-authentication-with-authorization
Installing dependencies from lock file (including require-dev)
Verifying lock file contents can be installed on current platform.
Your lock file does not contain a compatible set of packages. Please run composer update.

  Problem 1
    - laminas/laminas-component-installer is locked to version 2.1.2 and an update of this package was not requested.
    - laminas/laminas-component-installer 2.1.2 requires composer-plugin-api ^1.0 -> found composer-plugin-api[2.0.0] but it does not match the constraint.
  Problem 2
    - laminas/laminas-dependency-plugin is locked to version 0.2.0 and an update of this package was not requested.
    - laminas/laminas-dependency-plugin 0.2.0 requires composer-plugin-api ^1.1 -> found composer-plugin-api[2.0.0] but it does not match the constraint.
  Problem 3
    - dealerdirect/phpcodesniffer-composer-installer is locked to version v0.6.2 and an update of this package was not requested.
    - dealerdirect/phpcodesniffer-composer-installer v0.6.2 requires composer-plugin-api ^1.0 -> found composer-plugin-api[2.0.0] but it does not match the constraint.
  Problem 4
    - ocramius/package-versions is locked to version 1.4.2 and an update of this package was not requested.
    - ocramius/package-versions 1.4.2 requires composer-plugin-api ^1.0.0 -> found composer-plugin-api[2.0.0] but it does not match the constraint.
  Problem 5
    - laminas/laminas-component-installer 2.1.2 requires composer-plugin-api ^1.0 -> found composer-plugin-api[2.0.0] but it does not match the constraint.
    - mezzio/mezzio-tooling 1.3.0 requires laminas/laminas-component-installer ^2.0 -> satisfiable by laminas/laminas-component-installer[2.1.2].
    - mezzio/mezzio-tooling is locked to version 1.3.0 and an update of this package was not requested.

ocramius/package-versions only provides support for Composer 2 in 1.8+, which requires PHP 7.4.
If you can not upgrade PHP you can require composer/package-versions-deprecated to resolve this with PHP 7.0+.

You are using Composer 2, which some of your plugins seem to be incompatible with. Make sure you update your plugins or report a plugin-issue to ask them to support Composer 2.

For the valid /login route, why does the app execute middleware placed after the DispatchMiddleware in the pipeline?

I am experiencing an issue where I think the app may be behaving incorrectly, or maybe there is a special routing issue happening that I am not considering.

My belief is that if I hit a valid route, such as /login with the app, the pipeline should never go past DispatchMiddleware.php, and any middleware placed afterwards should not be executed. In my case, /login route goes past DispatchMiddleware.php, executing my custom middleware and I want to understand why.

To duplicate the behavior I am experiencing:

  • Create src/App/Middleware/LegacyApplicationMiddleware.php with code below:
declare(strict_types = 1);
namespace App\Middleware;

use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\ServerRequestInterface;
use Psr\Http\Server\MiddlewareInterface;
use Psr\Http\Server\RequestHandlerInterface;

class LegacyApplicationMiddleware implements MiddlewareInterface
{
    public function process(ServerRequestInterface $request, RequestHandlerInterface $handler): ResponseInterface
    {
        die("why do we get here?");
    }
}
  • Place the new middleware after DispatchMiddleware:
$app->pipe(DispatchMiddleware::class);
$app->pipe(LegacyApplicationMiddleware::class);
  • Place new middleware into config under 'factories' key:
LegacyApplicationMiddleware::class => InvokableFactory::class
  • Run the app and attempt to log in using any valid username and password

Expectation
After logging in, you should be able to see the default "Welcome to mezzio" login page with the message on top stating "You are succesfully authenticated"

Actual behavior
After login attempt, instead of the welcome page, you see the message "why do we get here?", because LegacyApplicationMiddleware is being executed after the DispatchMiddleware, despite /login being a valid route. My understanding is that a legal route should be entirely serviced by the DispatchMiddleware and go no further than that in the execution of the pipeline.php

Why is my middleware being executed? The intent of my middleware is to only work when I try to load a route that has not been specified in my config, that normally would result in 404 Not Found error. In this case, /login route is found, and should not result in 404 error. I say 404 error, because normally NotFoundHandler will be executed after DispatchMiddleware. In my case, LegacyApplicationMiddleware is being executed first

Can you help explain what's going on? Is that a quirk of the /login route specifically? Is it a malfunction/discrepancy of the mezzio-authentication-with-authorization? Something else?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.