3

The basic authentication provider service uses the user.auth service:

basic_auth.authentication.basic_auth:
    class: Drupal\basic_auth\Authentication\Provider\BasicAuth
    arguments: ['@config.factory', '@user.auth', '@flood', '@entity.manager']
    tags:
      - { name: authentication_provider, provider_id: 'basic_auth', priority: 100 }

I wrote an own service my-user.auth (extending UserAuthInterface) and want my service to be injected into the basic authentication provider instead of the user.auth. How can I do this?

  • Are you sure that you only want to change what is injected to basic auth authentication? What about all the other cases like a normal login? Might make more sense in your case to just alter the user.auth service and replace it with your own implementation? – Berdir Mar 4 '18 at 22:35
  • You are absolutely right, I want to alter the user.auth service, therefore I wrote an own one, and now I am trying to replace it everywhere it is used. Is there a way to alter it directly? – Matthias Mar 5 '18 at 8:42
  • 1
    Sure, in exactly the same way as the answer here, just alter that service and call setClass(), possibly with different arguments. – Berdir Mar 5 '18 at 9:11
  • Thanks, I think this makes much more sense in my case. Is there any priority handling? What happens if multiple modules alter the same service? – Matthias Mar 5 '18 at 9:54
  • Service builders are called based on the module weight I think. Obviously, a change like setClass() can only be done by one module and the one called last will win. There is a concept called service decorator, which allows you to define a service that is wrapping the original service. Then in theory multiple decorators can be combined, but this only makes sense if you only want to do something additional to the default behavior, if you do not call the inner service then you are still having a conflict – Berdir Mar 7 '18 at 13:59
4

Create a ServiceProvider in your module. And then replace the argument using Definition::replaceArguments like so:

<?php

namespace Drupal\my_module;

use Drupal\Core\DependencyInjection\ContainerBuilder;
use Drupal\Core\DependencyInjection\ServiceProviderBase;

// @note: You only need Reference, if you want to change service arguments.
use Symfony\Component\DependencyInjection\Reference;

/**
 * Modifies the language manager service.
 */
class MyModuleServiceProvider extends ServiceProviderBase {

  /**
   * {@inheritdoc}
   */
  public function alter(ContainerBuilder $container) {
    $definition = $container->getDefinition('basic_auth.authentication.basic_auth');
    $definition->replaceArgument(1, 'NEW_SERVICE');
  }
}

Please note:

Note that if you want this service alteration to be recognized automatically, the name of this class is required to be a CamelCase version of your module's machine name followed by ServiceProvider, it is required to be in your module's top-level namespace Drupal\your_module_name, and it must implement \Drupal\Core\DependencyInjection\ServiceModifierInterface (which ServiceProviderBase does).

Relevant article: https://www.drupal.org/docs/8/api/services-and-dependency-injection/altering-existing-services-providing-dynamic-services

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.