yii2-usuario icon indicating copy to clipboard operation
yii2-usuario copied to clipboard

usuario + AccessControl on Application throws User::identityClass must be set

Open cronfy opened this issue 8 years ago • 10 comments

I am trying to set global AccessControl on application. I have this in application configuration:

     'components' => [ ... ],

     'modules' => [
        'user' => [
            'class' => Da\User\Module::class,
        ]
    ],

    'as beforeRequest' => [
        'class' => \yii\filters\AccessControl::class,
        'ruleConfig' => [
            'class' => \Da\User\Filter\AccessRuleFilter::class,
        ],
        'rules' => [
            [ ... ],
        ],
    ],
],

It always throws User::identityClass must be set exception.

Is there any way to make it work?

cronfy avatar Sep 05 '17 13:09 cronfy

'modules' => [

        'user' => [
            'class' => Da\User\Module::class,
            'identityClass' => 'Da\User\Model\User'
        ]
    ],

Maybe, this help.

aka-VoV avatar Sep 05 '17 13:09 aka-VoV

@aka-VoV It does not.

I've found that usuario overrides yii\web\User here: https://github.com/2amigos/yii2-usuario/blob/master/src/User/Bootstrap.php#L145

But looks like it happens later than AccessControl behavior is initialized. So there is no identityClass at that time.

I tried this in application configuration:

    'container' => [
        'definitions' => [
            \yii\web\User::class =>                     [
                'enableAutoLogin' => true,
                'loginUrl' => ['/user/security/login'],
                'identityClass' => \Da\User\Model\User::class,
            ]

        ],
    ],

It works. But Da\User\Bootstrap has slighly more logic on this: it uses class map at initialization: 'identityClass' => $di->get(ClassMapHelper::class)->get(User::class), and I can't reproduce this logic in app's config. So I think I loose enhancement ability with this solution.

Can there be any better solution than overriding container definitions manually?

cronfy avatar Sep 05 '17 13:09 cronfy

Have you set the user component of your application? I think the problem is the initialization process of your application (https://github.com/yiisoft/yii2/blob/03299e8870eaaeb2714e53452078ca3ba2c86800/framework/web/User.php#L158). You can do the class map to the module but set your web user to the overridden model or the User model provided by this module.

tonydspaniard avatar Sep 05 '17 14:09 tonydspaniard

Have you set the user component of your application?

I haven't, because 1) usuario docs do not say to do it and 2) I see that usuario does this for me already.

You can do the class map to the module but set your web user to the overridden model

This is what I am doing now. I just hoped there was a way to make it all work automatically. Because "If you need to use AccessControl on Application with yii2-usuario, you must override yii\web\User manually" does not sound logical.

Maybe AccessControl initializes his $user just too early ? Should I file a bug report to yiisoft/yii2 on it? What do you think?

cronfy avatar Sep 05 '17 14:09 cronfy

I haven't, because 1) usuario docs do not say to do it and 2) I see that usuario does this for me already.

I know, the issue is with the initialization process that requires you to set the identity class. Is required by Yii not usuario. The model provided by the module implements the IdentityInterface required.

Maybe AccessControl initializes his $user just too early ? Should I file a bug report to yiisoft/yii2 on it? What do you think?

I would try before to fire the bootstrap process by setting 'bootstrap' => ['user'],? Let's see, otherwise, the problem is not on the module but on the application configuration and initialization.

If it doesn't work, lets see... But I don't think placing the User model on the config, shouldn't be an issue. I think they won't listen.

tonydspaniard avatar Sep 05 '17 14:09 tonydspaniard

I would try before to fire the bootstrap process by setting 'bootstrap' => ['user']

Currently it does not work. Here are the reasons:

  1. yii\web\Application has it's core component user: https://github.com/yiisoft/yii2/blob/master/framework/web/Application.php#L199
  2. yii\base\Application::bootstrap(), when looking for an object to initialize, first searches through components, and then through modules: https://github.com/yiisoft/yii2/blob/master/framework/base/Application.php#L312
  3. Thus, yii's core user component is bootstraped instead of usuario.
  4. Could be solved by using another name for usuario module, say 'modules' => [ 'usuario' => [ ... ] ], but 'user' module name is hardcoded in usuario: https://github.com/2amigos/yii2-usuario/blob/master/src/User/Bootstrap.php#L263

So, no way to initialize 'user' module instead of 'user' component, no way no rename 'user' module to something else. Impasse.

cronfy avatar Sep 05 '17 15:09 cronfy

@cronfy the components have nothing to do with the modules. Unfortunately, I just saw that the preInit() (https://github.com/yiisoft/yii2/blob/master/framework/base/Application.php#L258) is called prior the initialization (https://github.com/yiisoft/yii2/blob/master/framework/base/Application.php#L273) so, the only solution would be to set the 'components' => ['user' => ['class' => '\Da\User\Model\User']]

tonydspaniard avatar Sep 05 '17 15:09 tonydspaniard

@tonydspaniard Ok, one more question. The hardcoded 'user' module name in Da\User\Bootstrap - what are reasons for this? If it would not be hardcoded, we could safely rename the module and bootstrap it.

cronfy avatar Sep 05 '17 15:09 cronfy

How would you do it then? We require access to the module... would you add a loop? Feel free for a PR: https://github.com/2amigos/yii2-usuario/blob/master/src/User/Traits/ModuleAwareTrait.php#L27

tonydspaniard avatar Sep 05 '17 16:09 tonydspaniard

@tonydspaniard I can give it a try, but first let's try some luck here: https://github.com/yiisoft/yii2/issues/14766

cronfy avatar Sep 06 '17 09:09 cronfy