Asked  8 Months ago    Answers:  5   Viewed   41 times

I installed ZFCUser successfully. Now I wonder if there is a way to globally check for authentication.

As outlined in the wiki there are several ways to check for auth. They all work but do I have to put the check-if-clause really in every single action? All my sites should be only accessable when beeing logged in and if not, you should be rerouted to the login page.

Does anybody know if there's a central place where I can put this logic?

 Answers

65

To be honest, I don't think it is a good idea to block every page for a non-authenticated user. How would you access the login page?

That said, you must know the page being accessed, to make a whitelist of pages accessible for anonymous visitors. To start, I'd suggest to include the login page. You can check pages the easiest by using their route. So check the current matched route against the whitelist. If blocked, act upon. Otherwise, do nothing.

An example would be inside a Module.php from a module, for example your application:

namespace Application;

use ZendMvcMvcEvent;
use ZendMvcRouterRouteMatch;

class Module
{
    protected $whitelist = array('zfcuser/login');

    public function onBootstrap($e)
    {
        $app = $e->getApplication();
        $em  = $app->getEventManager();
        $sm  = $app->getServiceManager();

        $list = $this->whitelist;
        $auth = $sm->get('zfcuser_auth_service');

        $em->attach(MvcEvent::EVENT_ROUTE, function($e) use ($list, $auth) {
            $match = $e->getRouteMatch();

            // No route match, this is a 404
            if (!$match instanceof RouteMatch) {
                return;
            }

            // Route is whitelisted
            $name = $match->getMatchedRouteName();
            if (in_array($name, $list)) {
                return;
            }

            // User is authenticated
            if ($auth->hasIdentity()) {
                return;
            }

            // Redirect to the user login page, as an example
            $router   = $e->getRouter();
            $url      = $router->assemble(array(), array(
                'name' => 'zfcuser/login'
            ));

            $response = $e->getResponse();
            $response->getHeaders()->addHeaderLine('Location', $url);
            $response->setStatusCode(302);

            return $response;
        }, -100);
    }
}
Wednesday, March 31, 2021
 
SpiderLinked
answered 8 Months ago
58

I still haven't come around to write the tutorial for that :S

I don't know if this is working with the annotationbuilder though! As the DoctrineModuleFormElementObjectSelect needs the EntityManager to work. The options for the ObjectSelect are as follows:

   $this->add(array(
        'name'       => 'formElementName',
        'type'       => 'DoctrineModuleFormElementObjectSelect',
        'attributes' => array(
            'required' => true
        ),
        'options'    => array(
            'label'           => 'formElementLabel',
            'empty_option'    => '--- choose formElementName ---',
            'object_manager'  => $this->getEntityManager(),
            'target_class'    => 'MynamespaceEntityEntityname',
            'property'        => 'nameOfEntityPropertyAsSelect'
        )
    ));

In this case i make use of $this->getEntityManager(). I set up this dependency when calling the form from the ServiceManager. Personally i always do this from FactoryClasses. My FormFactory looks like this:

public function createService(ServiceLocatorInterface $serviceLocator)
{
    $em = $serviceLocator->get('DoctrineORMEntityManager');

    $form = new ErgebnishaushaltProduktForm('ergebnisform', array(
        'entity_manager' => $em
    ));

    $classMethodsHydrator = new ClassMethodsHydrator(false);

    // Wir fügen zwei Strategien, um benutzerdefinierte Logik während Extrakt auszuführen
    $classMethodsHydrator->addStrategy('produktBereich', new StrategyProduktbereichStrategy())
                         ->addStrategy('produktGruppe', new StrategyProduktgruppeStrategy());

    $hydrator = new DoctrineEntity($em, $classMethodsHydrator);

    $form->setHydrator($hydrator)
         ->setObject(new ErgebnishaushaltProdukt())
         ->setInputFilter(new ErgebnishaushaltProduktFilter())
         ->setAttribute('method', 'post');

    return $form;
}

And this is where all the magic is happening. Magic, that is also relevant to your other Thread here on SO. First, i grab the EntityManager. Then i create my form, and inject the dependency for the EntityManager. I do this using my own Form, you may write and use a Setter-Function to inject the EntityManager.

Next i create a ClassMethodsHydrator and add two HydrationStrategies to it. Personally i need to apply those strategies for each ObjectSelect-Element. You may not have to do this on your side. Try to see if it is working without it first!

After that, i create the DoctrineEntity-Hydrator, inject the EntityManager as well as my custom ClassMethodsHydrator. This way the Strategies will be added easily.

The rest should be quite self-explanatory (despite the german classnames :D)

Why the need for strategies

Imo, this is something missing from the DoctrineEntity currently, but things are still in an early stage. And once DoctrineModule-Issue#106 will be live, things will change again, probably making it more comfortable.

A Strategy looks like this:

<?php
namespace HaushaltportalStdlibHydratorStrategy;

use ZendStdlibHydratorStrategyStrategyInterface;

class ProduktbereichStrategy implements StrategyInterface
{
    public function extract($value)
    {
        if (is_numeric($value) || $value === null) {
            return $value;
        }

        return $value->getId();
    }

    public function hydrate($value)
    {
        return $value;
    }
}

So whenever the $value is not numeric or null, meaning: it should be an Object, we will call the getId() function. Personally i think it's a good idea to give each Element it's own strategy, but if you are sure you won't be needing to change the strategy at a later point, you could create a global Strategy for several elements like DefaultGetIdStrategy or something.

All this is basically the good work of Michael Gallego aka Bakura! In case you drop by the IRC, just hug him once ;)

Edit An additional resource with a look into the future - updated hydrator-docs for a very likely, soon to be included, pull request

Wednesday, March 31, 2021
 
Norgul
answered 8 Months ago
22

The problem has been solved thanks to @samsonasik comment to another question.

public function checkAuth(MvcEvent $e){
    # ... get auth service 
    if (!$auth->hasIdentity()) {
        $e->getRouteMatch()
                     ->setParam('controller', 'zfcuser')
                     ->setParam('action', 'login');
    }
    return;
}

So I have changed route without external redirection.

Wednesday, March 31, 2021
 
twk
answered 8 Months ago
twk
68

Don't know if it will help, but instead of prefix you can wrap elements in form or fieldset with form/fieldset name.

You just need to have a name of form or set it and then use setWrapElements

$form->setName('some_name');
$form->setWrapElements(true);
$form->prepare();

from this point full name of element, for example 'password' will be "some_name['password']"

If you are using annotations you can use this with combination of ComposedObject. It's very good explained here: http://devblog.x2k.co.uk/using-the-composedobject-zend-framework-2-form-annotation/

Martin

Wednesday, March 31, 2021
 
supermitch
answered 8 Months ago
38

ZendLdap is not included any more in a default installation. As the ZendFramework-Team has splitted the zendframework into multiple components not all of them are needed any more. And ZendLdap is one of the "not needed" ones as it has a hard dependency on ext/ldap as you can't use it without the LDAP-extension of PHP. For details on that have a look at https://github.com/zendframework/zf2/issues/7569

You should therefore run composer require zendframework/zend-ldap from the base-directory of your project and you should be up and running. By now you get that as a suggestions after the installation.

zendframework/zendframework suggests installing zendframework/zend-ldap (zend-ldap component ~2.5.0, if you need LDAP features)
Saturday, May 29, 2021
 
BetaRide
answered 5 Months ago
Only authorized users can answer the question. Please sign in first, or register a free account.
Not the answer you're looking for? Browse other questions tagged :
 
Share