0

I want to programmatically log in a user with a custom controller. I want to pass my data with $_POST to the route (I pass data from a mobile application); if username and password are correct, the method/function should return TRUE.

The route is the following one.

tcdev.login:
  path: '/tclogin'
  defaults:
    _controller: 'Drupal\tcdev\Controller\MYCenterController::login'
    _title: 'Login call back'
  requirements:
    _permission: 'access content'

The code for the controller is the following one.

namespace  Drupal\tcdev\Controller;

use Drupal\Core\Controller\ControllerBase;
use Symfony\Component\DependencyInjection\ContainerInterface;

class MyController extends ControllerBase {

    /**
     * \Drupal\user\UserAuth definition.
     *
     * @var \Drupal\user\UserAuth
     */
    protected $userAuth;

    /**
     * {@inheritdoc}
     */
    public function __construct(UserAuth $user_auth) {
        $this->userAuth = $user_auth;
    }

    /**
     * {@inheritdoc}
     */
    public static function create(ContainerInterface $container) {
        return new static($container->get('user.auth'));
    }
    }

    public function login() {
        $uid = $this->userAuth->authenticate($_POST['user'], $_POST['pass']);
        $acc = User::load($uid);

        //return new Response('Hi ' . $uid);
    }

}

It returns me the following error:

TypeError: Argument 1 passed to Drupal\tcdev\Controller\MyController::__construct() must be an instance of Drupal\tcdev\Controller\UserAuth, instance of Drupal\user\UserAuth given, called in /Users/yms/Sites/devdesktop/gttc/modules/tcdev/src/Controller/MyController.php on line 32 in Drupal\tcdev\Controller\MyController::__construct() (line 23 of modules/tcdev/src/Controller/MyController.php)

Where is my mistake?

1

What is causing the TypeError you quoted is how you declare the arguments in the following method.

public function __construct(UserAuth $user_auth) {
  $this->userAuth = $user_auth;
}

Since you don't use any namespace for UserAuth, nor did you add use \Drupal\user\UserAuth; at the beginning of your code, PHP assumes the argument for the class constructor is an object of the Drupal\tcdev\Controller\UserAuth class because Drupal\tcdev\Controller is the namespace used from that file.
This is in conflict with the class of the object the constructor is actually receiving; that is why Drupal raises a TypeError exception.

Full-qualify the argument, or add the use line at the beginning of the file; either of them will fix the error.

1

It seems you use mistake annotation and you have to pass right arguments to your constructor.

add use Drupal\User\UserAuth; and then try

/**
 * \Drupal\user\UserAuth definition.
 *
 * @var UserAuth
 */
protected $userAuth;

/**
 * Constructs .
 *
 * @param UserAuth $user_auth
 *
 */
public function __construct(UserAuth $user_auth) {
    $this->userAuth = $user_auth;
}
1

Inject the user.auth in your controller:

$auth = $container->get('user.auth')

[edited to clarify injection basics:

In public static function create(ContainerInterface $container) add $container->get('user.auth') to the return new static(...) statement.

In public function __construct(...) add the $auth to the signature at the correct position. Then add a private (or protected) variable $auth to your controller and assign the value from __construct to it.

You may simplify that by using drupal console or drush. They can create the boiler plate code for you.

If you don't want to use injection, you may use $auth = \Drupal::service('user.auth');

But this has drawbacks in testability.

[end edit]

then call the authenticate func:

$uid = $auth->authenticate($username, $pass);

With the $uid load the user:

$acc = User::load($uid);

Then set the user into the session:

  \Drupal::currentUser()->setAccount($acc);
  \Drupal::logger('user')->notice('Session opened for %name.', array('%name' => $acc->getUsername()));

Should work. But I don't think that it is a good idea to pass around the password in the URL of your tcdev.login...

Edit: Sample Code (generated by drupal generate:controller)

namespace Drupal\preosuser\Controller;

use Drupal\Core\Controller\ControllerBase;
use Symfony\Component\DependencyInjection\ContainerInterface;
use Drupal\user\UserAuth;

/**
 * Class AuthController.
 *
 * @package Drupal\preosuser\Controller
 */
class AuthController extends ControllerBase {

  /**
   * Drupal\user\UserAuth definition.
   *
   * @var \Drupal\user\UserAuth
   */
  protected $userAuth;

  /**
   * {@inheritdoc}
   */
  public function __construct(UserAuth $user_auth) {
    $this->userAuth = $user_auth;
  }

  /**
   * {@inheritdoc}
   */
  public static function create(ContainerInterface $container) {
    return new static(
      $container->get('user.auth')
    );
  }

  /**
   * Checklogin.
   *
   * @return string
   *   Return Hello string.
   */
  public function CheckLogin($name) {
    return [
      '#type' => 'markup',
      '#markup' => $this->t('Implement method: CheckLogin with parameter(s): $name'),
    ];
  }

}
  • and what is better solution? pass by $_POST ? – Yusef Mohamadi Jul 11 '16 at 6:03
  • Yes, at least. You could also use the standard Drupal Form API for this, take a look at the UserLoginTest Class for details. – Rainer Feike Jul 11 '16 at 6:12
  • tnx, I use $container = Drupal::getContainer(); to get contatiner but face with Error: Class 'Drupal\tcdev\Controller\Drupal' not found in Drupal\tcdev\C. – Yusef Mohamadi Jul 11 '16 at 6:54
  • can you tell me how can I get Container? – Yusef Mohamadi Jul 11 '16 at 7:38
  • You need to do this in the constructor of your Controller. This is injection basics, take a look at any other controller. I modify my answer to make it more clear. – Rainer Feike Jul 11 '16 at 7:39

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.