i have a LoginController like this:
public function loginAction(){
$db = $this->_getParam('db');
$this->_helper->viewRenderer->setNoRender();
$this->_helper->getHelper('layout')->disableLayout();
$adapter = new Zend_Auth_Adapter_DbTable(
$db,
'user',
'username',
'password',
'MD5(CONCAT(?,password_salt))'
);
$adapter->setIdentity($this->_request->getParam('username'));
$adapter->setCredential($this->_request->getParam('password'));
$auth = Zend_Auth::getInstance();
$result = $auth->authenticate($adapter);
if ($result->isValid()) {
// get all info about this user from the login table ommit only the password, we don't need that
$userInfo = $adapter->getResultRowObject(null, 'password');
$users = new Application_Model_DbTable_Users();
$users->updateLastlogin($userInfo->email);
$auth->setStorage(new Zend_Auth_Storage_Session('testzf'));
$authStorage = $auth->getStorage();
$authStorage->write($userInfo);
$data = array('login'=>'success');
}
and a ProfileController:
public function getprofileAction(){
$this->_helper->viewRenderer->setNoRender();
$this->_helper->getHelper('layout')->disableLayout();
if(Zend_Auth::getInstance()->hasIdentity()) {
$username=$this->_request->getParam('username');
$db_users = new Application_Model_DbTable_Users();
$user = $db_users->getUser($username);
}
i made AjaxCalls for both Login and getprofile actions. I can login but getprofile doesn't work because Zend_Auth::getInstance()->hasIdentity() returns null.
I see 2 session files in the folder as in application.ini. resources.session.save_path = APPLICATION_PATH "/../data/sessions"
First one is full of session data, the second one is empty 0KB.
Should this work through Ajax-Calls or i make an Error?
Regards
Since you've used a custom auth storage key in your login action (testzf), you'll need to set this whenever you want to access the auth data:
public function getprofileAction(){
$this->_helper->viewRenderer->setNoRender();
$this->_helper->getHelper('layout')->disableLayout();
$auth = Zend_Auth::getInstance();
$auth->setStorage(new Zend_Auth_Storage_Session('testzf'));
if($auth->hasIdentity()) {
$username=$this->_request->getParam('username');
$db_users = new Application_Model_DbTable_Users();
$user = $db_users->getUser($username);
}
}
Please use Zend_Auth_Storage_Session like
in your login action
// check ajax request
$result = array(
'error' => true,
'msg' => 'Something went wrong,please try again!'
);
if(!$this->_request->isXmlHttpRequest()){
$this->_helper->json->sendJson($result);
}
/**
* user authentication
*/
$authAdapter = new Zend_Auth_Adapter_DbTable(null,$this->_table_user);
$authAdapter->setIdentityColumn('user_name')
->setCredentialColumn('password');
$authAdapter->setIdentity($user_name)
->setCredential($password);
$select = $authAdapter->getDbSelect();
$select->where('status = ?',1);
$result = $authAdapter->authenticate($authAdapter);
/**
* user validate
*/
if($result->isValid()){
$userStorage = new Zend_Auth_Storage_Session('Zend_Auth_User','User_Storage');
$userData = $authAdapter->getResultRowObject();
$userStorage->write($userData );
$this->_helper->json->sendJson(array('error'=>false));
}
// in your profile action
/**
* you will get user session data through Zend_Auth_Storage_Session
* you can write this function in action controller you will get in your controller easily
like $this->_helper->json->sendJson(array('error'=>false));
*/
$userStorage = new Zend_Auth_Storage_Session('Zend_Auth_User','User_Storage');
$userData = $userStorage->read();
suppose you need to check hasIdentity()
you should use default Zend_Auth_Storage_Session like
$userStorage = new Zend_Auth_Storage_Session();
// default namespace for auth storage (with out any namespace)
you used any namespace for in Zend_Auth_Storage_Session like Zend_Auth_Storage_Session('testzf') you need to set storage in $auth instance like
$auth = Zend_Auth::getInstance();
$auth->setStorage(new Zend_Auth_Storage_Session('testzf'));
$auth->hasIdentity(); // you will get storage here
Related
I'm preparing joomla plugin/api to connect website with mobileapp. I cannot use cookies, I need to do this only by request.
So to login I can go to http://example.net/?user=aaa&pass=bbb and it creates session and returns token.
To go to user profile I can go to: http://example.net/profile?token=8asd7g... and if token matches session id in database then it sets session cookie (on php side) in Joomla framework
Which event should I use to:
check token and maintain session
check login, user and login/create session
check login, user and register user
The second question is how:
is it enought to set $session->set('userid',$user->id); ?
I create fake $response and $app->triggerEvent('onUserLogin', array((array) $response, array('action' => 'core.login.admin'))); is it enough?
If somebody need here is almost fnished solution. It allows users to login via user and pass taken form url or request header, it allows access to restricted parts of website based on token i url not cookie, it allows to pass params from header to JInput->get.
<?php
/**
* #package API
* #subpackage System.sittetokenlogin
*
*/
defined('_JEXEC') or die('Unauthorized Access');
jimport('joomla.filesystem.file');
class PlgSystemSittetokenlogin extends JPlugin
{
public function __construct(&$subject, $config)
{
parent::__construct($subject, $config);
}
public function onUserAuthenticate()
{
//die('onUserAuthenticate');
}
public function onUserLogin()
{//wykonuje się
//die('onUserLogin');
}
public function onUserLogout()
{//wykonuje się
//die('onUserLogout');
}
public function onAfterInitialise()
{
//wstępne ustawienie obiektów
$app = JFactory::getApplication();
if ($app->isClient('administrator')) return;
$input = JFactory::getApplication()->input;
$headers = getallheaders ();
$db = JFactory::getDbo();
//pobranie danych z rządania
$loginToken = $headers['logintoken']; if(!$loginToken) $loginToken = $input->get->get('logintoken', '', 'STRING');
$suser = $headers['suser']; if(!$suser) $suser = $input->get->get('suser', '', 'STRING');
$spass = $headers['spass']; if(!$spass) $spass = $input->get->get('spass', '', 'STRING');
if ($loginToken) // logowanie na bazie tokenu
{
JPluginHelper::importPlugin('user');
$sesja = $db->setQuery('SELECT * FROM `#__session` WHERE `session_id`='.$db->quote($loginToken).' LIMIT 1')->loadObject();
$user = $db->setQuery('SELECT * FROM `#__users` WHERE `id`='.$db->quote($sesja->userid).' LIMIT 1')->loadObject();
$response = new JAuthenticationResponse();
$response->type = 'Joomla';
$response->email = $user->email;
$response->fullname = $user->name;
$response->username = $user->username;
$response->password = '';
$response->status = JAuthentication::STATUS_SUCCESS;
$response->error_message = null;
//print_r($response);
$app->triggerEvent('onUserLogin', array((array) $response, array('action' => 'core.login.site')));
//$testuser = JFactory::getUser(); die(print_r($testuser,true));
}
elseif ($suser && $spass) //logowanie na bazie loginu i hasła
{
$error = $app->login([
'username' => $suser,
'password' => $spass,
]);
$user = JFactory::getUser();
if ($user->id>0) die(JFactory::getSession()->getId());
else die('login_error');
}
//przekazywanie parametrów
$option = $headers['option']; $input->set('option',$option);
$view = $headers['view']; $input->set('view',$view);
$id = $headers['id']; $input->set('id',$id);
$catid = $headers['catid']; $input->set('catid',$catid);
$Itemid = $headers['Itemid']; $input->set('Itemid',$Itemid);
$tmpl = $headers['tmpl']; $input->set('tmpl',$tmpl);
//$input->set('option','com_guru');
//$input->set('view','gurupcategs');
}
}
I'm using yii2-dektrium to allow users login with their facebook's accounts.
After the login is done, I need to make API request from my server to get data of the user's accounts. One example of request is:
$client = Yii::$app->authClientCollection->getClient('facebook');
$response = $client->createApiRequest()
->setMethod('GET')
->setUrl('v2.12/me/accounts')
->send();
The access_token is saved on session so I need to persist it to the database.
I already added a column access_token to the social_account default table of yii2-dektrium but I don't know how to get and save it, and further more, how to apply it to the requests.
After reading for a while. I think the way to save it is overriding the method connect in dektrium\user\controllers\SecurityController.
public function connect(ClientInterface $client)
{
/** #var Account $account */
$account = \Yii::createObject(Account::className());
$event = $this->getAuthEvent($account, $client);
$this->trigger(self::EVENT_BEFORE_CONNECT, $event);
$account->connectWithUser($client);
$this->trigger(self::EVENT_AFTER_CONNECT, $event);
$this->action->successUrl = Url::to(['/user/settings/networks']);
}
And for applying to the request, override applyAccessTokenToRequest on yii\authclient\clients\Facebook
public function applyAccessTokenToRequest($request, $accessToken)
{
parent::applyAccessTokenToRequest($request, $accessToken);
$data = $request->getData();
if (($machineId = $accessToken->getParam('machine_id')) !== null) {
$data['machine_id'] = $machineId;
}
$data['appsecret_proof'] = hash_hmac('sha256', $accessToken->getToken(), $this->clientSecret);
$request->setData($data);
}
I can't get it done. And I'm not sure if it is the right way to do it. What I'm missing?
For save the access_token the first time you have to overwrite the connect action from \dektrium\user\controllers\SecurityController.
class SecurityController extends \dektrium\user\controllers\SecurityController
{
public function connect(ClientInterface $client)
{
// default implementation of connect
$account = \Yii::createObject(Account::className());
$event = $this->getAuthEvent($account, $client);
$this->trigger(self::EVENT_BEFORE_CONNECT, $event);
$account->connectWithUser($client);
$this->trigger(self::EVENT_AFTER_CONNECT, $event);
// get acess_token from $client
$access_token['tokenParamKey'] = $client->getAccessToken()->tokenParamKey;
$access_token['tokenSecretParamKey'] = $client->getAccessToken()->tokenSecretParamKey;
$access_token['createTimestamp'] = $client->getAccessToken()->createTimestamp;
$access_token['_expireDurationParamKey'] = $client->getAccessToken()->getExpireDurationParamKey();
$access_token['_params'] = $client->getAccessToken()->getParams();
// save acess_token to social_account table
$model = SocialAccount::find()->where(['provider' => $client->getName()])->andWhere(['user_id' => Yii::$app->user->id])->one();
$model->access_token = \yii\helpers\Json::encode($access_token);
$model->save(false);
$this->action->successUrl = Url::to(['/user/settings/networks']);
}
}
To get the access_token store in the database for further API Requests create a class that extends yii\authclient\SessionStateStorage and overwrite get method.
namespace app\models\authclient;
class DbStateStorage extends SessionStateStorage
{
public function get($key)
{
// $key is a complex string that ends with 'token' if the value to get is the actual access_token
$part = explode('_', $key);
if (count($part) == 3 && $part[2] == 'token') {
$account = SocialAccount::find()
->where(['provider' => $part[1]])
->andWhere(['user_id' => Yii::$app->user->id])
->one();
if ($account != null) {
$access_token = json_decode($account->access_token);
$token = new \yii\authclient\OAuthToken();
$token->createTimestamp = $access_token->createTimestamp;
$token->tokenParamKey = $access_token->tokenParamKey;
$token->tokenSecretParamKey = $access_token->tokenSecretParamKey;
$token->setParams((array)$access_token->_params);
$token->setExpireDurationParamKey($access_token->_expireDurationParamKey);
return $token;
}
}
if ($this->session !== null) {
return $this->session->get($key);
}
return null;
}
}
Finally set the DbStateStorage to your authclient
class Facebook extends \dektrium\user\clients\Facebook
{
public function __construct()
{
$this->setStateStorage('app\models\authclient\DbStateStorage');
}
}
I am getting below error while running Login Authentication Code on. I am using zend framework & zend studio as IDE
A value for the identity was not provided prior to authentication with
Zend_Auth_Adapter_DbTable.
Below is the code which i have written:
public function authAction(){
$request = $this->getRequest();
$registry = Zend_Registry::getInstance();
$auth = Zend_Auth::getInstance();
$DB = $registry['zenddb']; //zenddb is database name
$authAdapter = new Zend_Auth_Adapter_DbTable($DB);
$authAdapter->setTableName('user');
$authAdapter->setIdentityColumn('user_name');
$authAdapter->setCredentialColumn('password');
// Set the input credential values
$uname = $request->getParam('user_name');
$paswd = $request->getParam('password');
$authAdapter->setIdentity($uname);
$authAdapter->setCredential(md5($paswd));
// Perform the authentication query, saving the result
$result = $auth->authenticate($authAdapter);
if($result->isValid()){
$data = $authAdapter->getResultRowObject(null,'password');
$auth->getStorage()->write($data);
$this->_redirect('userpage');
}else{
$this->_redirect('login');
}
}
This error usually occurs when you leave the credential fields blank in your form,
so zend rectifies is with a catch block which throws the error which you mentioned.
Official Ticket
you can solve it by putting validation on field related to the empty fields. // e.g. 'required' => true
hope it helps.
public function loginAction()
{
$this->_helper->layout->setLayout('loginlayout');
$request = $this->getRequest();
$form = new Application_Form_loginForm();
$login="";
if ($this->getRequest()->isPost()) {
if ($form->isValid($request->getPost())) {
$request = $this->getRequest();
// Set the input credential values
$registry = Zend_Registry::getInstance();
$auth = Zend_Auth::getInstance();
$params = array('host' =>'localhost',
'username' =>'root',
'password' =>'',
'dbname' =>'zendDb'
);
$DB = new Zend_Db_Adapter_Pdo_Mysql($params);
$authAdapter = new Zend_Auth_Adapter_DbTable($DB);
$authAdapter->setTableName('user');
$authAdapter->setIdentityColumn('user_name');
$authAdapter->setCredentialColumn('password');
$request = $this->getRequest();
// Set the input credential values
$uname = $request->getParam('user_name');
$paswd = $request->getParam('password');
$authAdapter->setIdentity($uname);
$authAdapter->setCredential(md5($paswd));
$auth = Zend_Auth::getInstance();
// Perform the authentication query, saving the result
$result = $auth->authenticate($authAdapter);
if($result->isValid()){
$data = $authAdapter->getResultRowObject(null,'password');
$auth->getStorage()->write($data);
$login="";
$this->_redirect('database/user');
}else{
$login="Invalid User Name or Password";
//$this->_redirect('database/login');
}
//return $this->_helper->redirector('auth');
}
}
else {
$login="";
}
$this->view->assign('title','Login');
$this->view->assign('description',$login);
$this->view->form = $form;
}
if ($this->getRequest()->isPost()) {
if ($form->isValid($request->getPost())){
//Simply Wrap your Code between this two conditions.
}
}
As you can see here:
First you have to check whether the request is POST or not.
Second than you have to check whether it's valid for your form or not.
why i cant get user as object ?
i use code to get user identity :
$identity = Zend_Auth::getInstance()->getIdentity()
echo $identity->usergroup
return Notice: Trying to get property of non-object
or
$identity = Zend_Auth::getInstance()->getStorage()->read();
var_dump($identity);
give string 'test#g.pl' (length=9)
so how to get usergroup
login :
$request = $this->getRequest();
if ($request->isPost() and $loginForm->isValid($_POST)) {
$adapter = new Zend_Auth_Adapter_DbTable(
$db,
'users',
'useremail',
'password'
);
$adapter->setIdentity($loginForm->getValue('useremail'));
$adapter->setCredential($loginForm->getValue('password'));
$auth = Zend_Auth::getInstance();
$result = $auth->authenticate($adapter);
if ($result->isValid()) {
$this->_helper->FlashMessenger('Successful Login');
$this->_redirect('/');
return;
}else{
throw new Exception($result->getMessages()[0]);
}
user model :
protected $_id;
protected $_useremail;
protected $_usergroup;
protected $_password;
protected $_password_salt;
protected $_realname;
you can use,
$auth = Zend_Auth::getInstance();
$result = $auth->authenticate($adapter);
if ($result->isValid()) {
$user = $adapter->getResultRowObject();
$auth->getStorage()->write($user);
return true;
}
if usergroup is in the row that authenticates user,
you can use this,
$auth = Zend_Auth::getInstance();
$usergroup = $auth->getIdentity()->usergroup;
or another field for that matter like,
$password = $auth->getIdentity()->password;
Or
$email = $auth->getIdentity()->email;
Use this article by rob allen to understand more, here
That is the normal behavior, in fact the getIdentity method returns the identity of the user, that is, the username.
Please try to Auth session data
$identity = Zend_Auth::getInstance()->getStorage()->read();
var_dump($identity)
Zend_Auth::getInstance()->getIdentity() is return $username name only
I have a log in form that checks the user email and password through the database, if it matches, it allow the user to log in. The problem is it checks the email that matches any password in the database or the password that matches any emails in the database. I want it to check this specific user email to match his password, not matches any password that exists in database.
Here's my controller that I think I did it wrong:
$loginForm = new Application_Form_UserLogin();
if ($this->getRequest()->isPost('loginForm'))
{
$email_adrress = $this->getRequest()->getParam('email_address');
$password = $this->getRequest()->getParam('password');
/************ Login Form ************/
if ($loginForm->isValid($this->getRequest()->getParams()))
{
$user = $this->_helper->model('Users')->createRow($loginForm->getValues());
$user = $this->_helper->model('Users')->fetchRowByFields(array('email' => $email_adrress, 'hash' => $password));
if($user)
{
Zend_Session::rememberMe(86400 * 14);
Zend_Auth::getInstance()->getStorage()->write($user);
$this->getHelper('redirector')->gotoRoute(array(), 'invite');
return;
}
else {
}
}
}$this->view->loginForm = $loginForm;
My form:
class Application_Form_UserLogin extends Zend_Form
{
public $email, $password, $submit;
public function init()
{
$this->setName('loginForm');
$EmailExists = new Zend_Validate_Db_RecordExists(
array(
'table' => 'users',
'field' => 'email'
)
);
//$EmailExists->setMessage('Invalid email address, please try again. *');
$PasswordExists = new Zend_Validate_Db_RecordExists(
array(
'table' => 'users',
'field' => 'hash'
)
);
$PasswordExists->setMessage('Invalid password, please try again. *');
$this->email = $this->createElement('text', 'email_address')
->setLabel('Email')
->addValidator($EmailExists)
->addValidator('EmailAddress')
->setRequired(true);
$this->password = $this->createElement('text', 'password')
->setLabel('Password')
->addValidator($PasswordExists)
->setRequired(true);
$this->submitButton = $this->createElement('button', 'btn_login')
->setLabel('Login')
->setAttrib('type', 'submit');
$this->addElements(array($this->email, $this->password, $this->submit));
$elementDecorators = array(
'ViewHelper'
);
$this->setElementDecorators($elementDecorators);
}
}
I wouldn't add this login processing as a validator on one of the elements. Instead, I would create an Zend_Auth authentication adapter with your User model, email, and password as constructor arguments. Then, in controller, call Zend_Auth::authenticate($adapter).
Something like:
class Application_Model_AuthAdapter implements Zend_Auth_Adapter_Interface
{
protected $userModel;
protected $email;
protected $pass;
public function __construct($userModel, $email, $pass)
{
$this->userModel = $userModel;
$this->email = $email;
$this->pass = $pass;
}
public function authenticate()
{
$user = $this->userModel->getByEmailAndPassword($this->email, $this->pass);
if ($user){
return new Zend_Auth_Result(Zend_Auth_Result::SUCCESS, $user);
} else {
return new Zend_Auth_Result(Zend_Auth_Result::FAILURE_CREDENTIAL_INVALID, null);
}
}
}
Then in your controller:
public function loginAction()
{
$form = new Application_Form_UserLogin();
if ($this->_request->isPost()) {
if ($form->isValid($this->_request->getPost())) {
$data = $form->getValues();
$email = $data['email'];
$pass = $data['pass'];
$userModel = $this->_helper->model('Users');
$authAdapter = new Application_Model_AuthAdapter($userModel, $email, $pass);
$result = Zend_Auth::getInstance()->authenticate($adapter);
if ($result->isValid()){
// $user= $result->getIdentity(). Use it how you like.
// Redirect someplace
} else {
$this->view->error = 'Invalid login';
}
}
}
$this->view->form = $form;
}
See Zend_Auth reference for more details.
I'm not familiar with the way you're trying to do it. Is the fetchRowByFields method one you have written yourself? If so, it's difficult to help you without seeing the code.
Have you considered using the mechanism provided by Zend Framework to perform authentication against a database?
The Zend Framework official manual contains a brief tutorial on how to implement authentication:
http://framework.zend.com/manual/1.12/en/learning.multiuser.authentication.html
You use an adapter with the Zend_Auth class to do what you want.