开发者

Joomla Login Authentication from external app

开发者 https://www.devze.com 2022-12-18 22:45 出处:网络
I need to check that a Joomla username and password is valid from my external application. It is not necessary that the user is logged into the system just that their account exists.How do I 开发者_开

I need to check that a Joomla username and password is valid from my external application. It is not necessary that the user is logged into the system just that their account exists. How do I 开发者_开发问答do this?


I'm supposing your external application will have access to Joomla's database and is written in php as well.

I've already answered a similar question about creating a user outside joomla, you could use the same approach, but instead of calling the save method from JUser, you could use bind to check if the password is correct.

Or something better: simply copy and paste Joomla's own authentication mechanism after creating an "environment" outside Joomla! Check JOOMLA_PATH/plugins/authentication/joomla.php:

 function onAuthenticate( $credentials, $options, &$response ){
  jimport('joomla.user.helper');
  // Joomla does not like blank passwords
  if (empty($credentials['password'])){
   $response->status = JAUTHENTICATE_STATUS_FAILURE;
   $response->error_message = 'Empty password not allowed';
   return false;
  }

  // Initialize variables
  $conditions = '';

  // Get a database object
  $db =& JFactory::getDBO();

  $query = 'SELECT `id`, `password`, `gid`'
   . ' FROM `#__users`'
   . ' WHERE username=' . $db->Quote( $credentials['username'] )
   ;
  $db->setQuery( $query );
  $result = $db->loadObject();

  if($result){
   $parts = explode( ':', $result->password );
   $crypt = $parts[0];
   $salt = @$parts[1];
   $testcrypt = JUserHelper::getCryptedPassword($credentials['password'], $salt);

   if ($crypt == $testcrypt) {
    $user = JUser::getInstance($result->id); // Bring this in line with the rest of the system
    $response->email = $user->email;
    $response->fullname = $user->name;
    $response->status = JAUTHENTICATE_STATUS_SUCCESS;
    $response->error_message = '';
   } else {
    $response->status = JAUTHENTICATE_STATUS_FAILURE;
    $response->error_message = 'Invalid password';
   }
  }
  else{
   $response->status = JAUTHENTICATE_STATUS_FAILURE;
   $response->error_message = 'User does not exist';
  }
 }


As a variation on @Martin's answer, a component could return the JUser object associated with the given credentials. The following component is tested in Joomla 2.5:
A view view.raw.php:

defined( '_JEXEC' ) or die( 'Restricted access' );

jimport( 'joomla.application.component.view' );

class ExtauthViewLogin extends JView
{
    function display( $tpl = null )
    {
        $username = JRequest::getVar( 'username', 'John Doe' );   
        $password = JRequest::getVar( 'password', 'rattlesnake' );   

        jimport('joomla.user.authentication');

        $app = JFactory::getApplication();

        $credentials = array( "username" => $username, "password" => $password);
        $options = array("silent" => true);

        $authorized = $app->logout(null, $options);
        $authorized = $app->login($credentials, $options);
        $user = JFactory::getUser();

        echo json_encode($user);
    }
}

Note the logout before the login. After a successful login, all subsequent calls with wrong credentials would still return the user of the first call, without the logout!
Also note the silent option. This makes the login function return gracefully with true or false, without spawning exceptions.
The controller.php:

defined( '_JEXEC' ) or die( 'Restricted access' );

jimport( 'joomla.application.component.controller' );

class ExtauthController extends JController
{
    function display($cachable = false, $urlparams = false) 
    {
        $view = JRequest::getVar( 'view', 'login' );
        $layout = JRequest::getVar( 'layout', 'default' );
        $format = JRequest::getVar( 'format', 'raw' );   

        $view = $this->getView( $view, $format );
        $view->setLayout( $layout );    

        $view->display(); 
    }
}

Note the raw format. This is needed to have joomla return the pure json code instead of the whole html page.
The component can be called (via ajax) with url:
index.php?option=com_extauth&task=view&format=raw&username=John&password=Doe

The returned JSON object will contain NULL values for most fields in case of an unsuccessful logon.

The full component is the simplest possible, based on com_hello without a model or tmpl.


You could equally write a API component such that you use a url to query the API and get a JSON response back e.g. http://www.domain.com/index.php?option=com_api&view=authenicateUser&user=root&password=12345&format=raw

Then you have a controller that picks up this view and calls the model or helper class which has code like below. The advantage of this is that you keep within the Joomla code base and make this more secure.

function __construct() {
  // params
  $this->username = JRequest::getVar('user', '');
  $this->password = JRequest::getVar('password', '');
  $this->checkParameters();
}

private function checkParameters() {
  // datatype checks
  if ($this->username == '') {
    die('ERROR: user is blank');
  }
  if ($this->password == '') {
    die('ERROR: password is blank');
  }
}  

function execute() {
  // Get the global JAuthentication object
  jimport( 'joomla.user.authentication');
  $auth = & JAuthentication::getInstance();
  $credentials = array( 'username' => $this->username, 'password' => $this->password );
  $options = array();
  $response = $auth->authenticate($credentials, $options);

  // success
  return ($response->status === JAUTHENTICATE_STATUS_SUCCESS) {
    $response->status = true;
  } else {
  // failed
    $response->status = false;
  }
  echo json_encode($response);
}


Your external app should be able to access the database of the joomla app to check in the database whether or not user exists/ is valid. To check it, you got to run some query in your external app to check the existence of the user something like this:

$query = "select user_id from your_table where user_id = id_here";
// and more code afterwords.


I don't know how secure it is, but I didn't fancy creating an API component and came up with this:

<?php

define("LOGIN_USER_DOES_NOT_EXIST", 0);
define("LOGIN_USER_OK_INCORRECT_PASSWORD", 1);
define("LOGIN_USER_OK_PASSWORD_OK", 2);
define("LOGIN_NO_AUTH_SERVER", 3);

$user = $_GET["id"];
$userpassword = $_GET["pw"];

$mysql = mysql_connect("localhost", "login", "password") or die(LOGIN_NO_AUTH_SERVER);
mysql_select_db("joomladb") or die(LOGIN_NO_AUTH_SERVER);
$query = "Select password FROM j25_users WHERE username='" . $user . "'";
$result = mysql_query($query) or die(LOGIN_NO_AUTH_SERVER);
if (mysql_num_rows($result) != 1) {
    $send = LOGIN_USER_DOES_NOT_EXIST;
} else {
    while ($line = mysql_fetch_array($result, MYSQL_ASSOC)) {
        foreach ($line as $col_value) {
            $hashparts = explode(':', $col_value);
            $userhash = md5($userpassword.$hashparts[1]);
            if ($userhash == $hashparts[0]) $send = LOGIN_USER_OK_PASSWORD_OK;
            else $send =  LOGIN_USER_OK_INCORRECT_PASSWORD;
        }
    }
}

echo $send;

mysql_free_result($result);
mysql_close();

?>

The result (only one character) can easily be parsed by any kind of app.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号