I have the following controller in ZF1 with a "logout" action:
class DefaultController extends Website_Controller_Action
{
//...
public function logoutAction()
{
try {
if ($this->user && $this->user instanceof \Transfer_User) {
$userLogin = new User_Login();
//set cookie here
$userLogin->logout($this->user);
}
Messages::addSuccess($this->view->translate('success_logout'));
$this->_redirect('/');
} catch (Exception $e) {
$this->_redirect('/');
}
}
//...
}
The action checks if the user is logged in and then does a logout. Before the logout is executed I want to set a cookie with some specific data that is read on the next login.
I tried setcookie(...) and new Zend_Http_Cookie(...) but both of them don't work. Is there any other way to set a cookie on a controller action in ZF1?
Thank you for your answers ;-)
Related
I have a controller like this:
class ArticleController extends Controller implements AuthControllerInterface
{
public function listAllArticleAction (Request $request)
{
// ... ignore
}
public function addArticleAction (Request $request)
{
// ... ignore
}
// ... another article control method
}
Users who want to add article must log in, however, user can visit listAllArticleAction without logging in.
I try to use Event Listener to solve the problem:
class AuthListener
{
private $m_router;
public function __construct(Router $router)
{
$this->m_router = $router;
}
public function onKernelController(FilterControllerEvent $event)
{
$controller = $event->getController();
if ($controller[0] instanceof AuthControllerInterface) {
$session = $event->getRequest()->getSession()->get('userId');
if (!isset($session)) {
$redirectUrl = $this->m_router->generate('page.login');
$event->setController(function () use ($redirectUrl){
return new RedirectResponse($redirectUrl);
});
}
}
}
}
If user doesn't login, user will be redirected to login page, however, this approach also takes effect on "listAllArticleAction" method.
I think that checking session at the start of the function is not a good idea, because I have another article control methods such as "deleteArticle", "getArticle" and so on, some of them need to log in first, and the others not.
How do I implement this function with event listener? Or, is there any better way to do this?
You're trying to do manually something that is already implemented in Symfony.
You have a two ways to do that. Take a look on documentation of Security Component
Use access_control section in security configuration (security.yml or via annotations)
See also How Does the Security access_control Work?
In YAML configuration it would be something like:
security:
access_control:
- { path: ^/path/to/add_article, roles: IS_AUTHENTICATED_REMEMBERED }
Check if used is logged at the begining of action
if (!$this->get('security.authorization_checker')->isGranted('IS_AUTHENTICATED_REMEMBERED')) {
throw $this->createAccessDeniedException();
}
The right way to do that is :
class ArticleController extends Controller
{
public function listAllArticleAction (Request $request)
{
// ... ignore
}
public function addArticleAction (Request $request)
{
if (!$this->get('security.authorization_checker')->isGranted('IS_AUTHENTICATED_FULLY')) {
throw $this->createAccessDeniedException();
}
// ... ignore
}
// ... another article control method
}
If your user is not logged in, they will be redirected to the login page
I have a static page I want to add to the existing cakePHP project. I managed to get around the Auth through using this code on PagesController
public $allowedPages = array('main',);
public function beforeFilter() {
$this->Auth->allow('display');
}
public function display()
{
$path = func_get_args();
$count = count($path);
if (!$count) {
return $this->redirect('/');
}
$page = $subpage = null;
if (!empty($path[0])) {
$page = $path[0];
}
if (!empty($path[1])) {
$subpage = $path[1];
}
$this->set(compact('page', 'subpage'));
/*add CHU
if(in_array($page, $this->allowedPages) || $this->User->loggedin) {
$this->render($page);
} */
if(in_array($page, $this->allowedPages) ) {
$this->render($page); //here redirects to login page change the path if the path is different
}
try {
$this->render(implode('/', $path));
} catch (MissingTemplateException $e) {
if (Configure::read('debug')) {
throw $e;
}
throw new NotFoundException();
}
}
And added the route like this:
$routes->connect('/main', ['controller' => 'Pages', 'action' => 'display', 'main']);
But what's happening is that when a user logs in, the login page displays again. I think a validation should be added to check if a user is logged in here:
if(in_array($page, $this->allowedPages) ) {
$this->render($page); //here redirects to login page change the path if the path is different
}
How can I do this?
I tried these answers:
Auth for static page
Allowing a Specific Page in Cakephp
I don't think it's necessary to go through so much hassle. For e.g: If the name of your action is "privacyPolicy", you could simply specify it within $this->Auth->allow() in AppController itself.
In case you'd like to keep it separated and write it within PagesController, I'd suggest you to call the parent function. Otherwise, the beforeFilter within PagesController overrides the beforeFilter of AppController.
//AppController.php
/* Other code */
public function beforeFilter() {
..........
$this->Auth->allow(array(
"action1",
"action2",
"display"
));
}
_____________________ OR ________________________________
// PagesController.php
public function beforeFilter() {
parent::beforeFilter(); // Add this line
$this->Auth->allow('display');
}
Hope this helps.
Peace! xD
I'm currently using Laravel 5 Authentification, but I have edited it to allow me to connect to an API server instead of an Eloquent model.
Here is the code of my custom UserProvider:
<?php namespace App\Auth;
use Illuminate\Contracts\Auth\UserProvider as UserProviderInterface;
use WDAL;
use Illuminate\Contracts\Auth\Authenticatable;
use Illuminate\Auth\GenericUser;
use Session;
class WolfUserProvider implements UserProviderInterface {
private $_loggedUser;
public function __construct()
{
$this->_loggedUser = null;
$user = Session::get('user');
if (!empty($user)) {
$this->_loggedUser = unserialize($user);
}
}
public function retrieveById($id)
{
return $this->_loggedUser;
}
public function retrieveByToken($identifier, $token)
{
return null;
}
public function updateRememberToken(Authenticatable $user, $token)
{
//dd('updateRememberToken');
}
public function retrieveByCredentials(array $credentials)
{
$user = WDAL::getContactCredentials($credentials['login']);
return $user;
}
public function validateCredentials(Authenticatable $user, array $credentials)
{
if($user->username == $credentials['login'] && $user->password == $credentials['password']){
$this->_loggedUser = $user;
Session::set('user', serialize($user));
return true;
}
else{
return false;
}
}
}
?>
This code might not be perfect as it still in early development ;-) (feel free to suggest me some ideas of improvement if you want to)
So when the user is logged, it has access to the whole platform and to several views and can communicate with the API server to display and edit data.
Sometimes, the API server can return "Invalid Session ID" and when my Model gets this message, the user should be redirected to the login page.
From a Controller it's really easy to handle I can use this code (logout link):
public function getLogout()
{
$this->auth->logout();
Session::flush();
return redirect('/');
}
But do you know how I should proceed from a Model ? I could of course edit all my controllers to check for the value returned by the Model to logout, but cannot it be done thanks to middlewares?
It seems to be really long to edit all my controllers, and this will imply a lot of duplicated code.
One of my tries was to throw an exception from the Controller, and catch in from the auth middleware.
It was not working, because I didn't write use Exception;
I'm now catching the exception, and can now redirect the user from the middleware.
Thank you anyway!
Ok, so I haven't had this issue in a while, but I've done most the options I can to resolve this and have read other people's posts. I'm at a lost right now.
After creating the controller, I did the "php ./composer.phar dump-autoload" command, saying it generated successfully, and it's still saying the controller doesn't exist. There are already 3 other controllers in the folder it's in, and each one of those works, it's just this controller that's having the problem.
Code to Controller: (/apps/controllers/api/apiBulkController.php)
class apiBulkController extends BaseController {
private $error;
public function __construct()
{
// Set default values
$this->error = 'false';
}
public function create()
{
$bulk = array();
// Authenticate the user using the api
if (!isset($_SERVER['PHP_AUTH_USER'])) {
$this->authenticate();
} else {
$auth = User::where('username', $_SERVER['PHP_AUTH_USER'])->first();
// Check to see if the user is valid
if(isset($auth->authkey) && $auth->authkey == $_SERVER['PHP_AUTH_PW'])
{
$req = Request::get();
$bulk = new Bulk;
// Add Columns by example below
$bulk->save();
//ex. $Bulk->Name = Request::get(''); $object->column_name = Request;
// Return JSON data
return Response::json(array(
'error' => $this->error
));
}
else
{
echo $_SERVER['PHP_AUTH_USER'].": Your hash seems to be incorrect.";
}
}
}
public function authenticate()
{
header('WWW-Authenticate: Basic realm="User Authentication (Username / Hash)"');
header('HTTP/1.0 401 Unauthorized');
echo "You must enter a valid Login ID and Hash to access this resource\n";
exit;
}
}
You should probably add
namespace api;
at the beginning of your controller
and run controller also using your namespace before class name, for example in Route api\apiBulkController#create instead of apiBulkController#create.
If error changes, you should then alter your class adding namespaces or uses to other classes for example instead of extends BaseController should be extends \BaseController and so on
I am trying to create a simple login using Yii Here is my auth controller
class AuthController extends Controller
{
/**
* Declare class-based actions.
*/
public function actionLogin()
{
$model = new LoginForm;
$post = Yii::app()->request->getPost('LoginForm');
// If form is submitted
if($post) {
$identity = new UserIdentity($post['username'], $post['password']);
echo $identity->testing();
if($identity->authenticate()) {
echo 'yes';
} else {
echo 'no';
}
exit;
}
$this->render('login', array('model' => $model));
}
}
And here is my UserIdentity
class UserIdentity extends CUserIdentity
{
private $_id;
public function authenticate()
{ echo 'testing';
$user = LoginForm::model()->findByAttributes(array('username' => $this->username));
if(is_null($user)) {
%this->errorCode=self::ERROR_USERNAME_INVALID;
} else if($user->password != $this->password) {
$this->errorCode=self::ERROR_PASSWORD_INVALID;
} else {
$this->_id = $user->id;
$this->errorCode=self::ERROR_NONE;
}
return !$this->errorCode;
}
function getId()
{
return $this->_id;
}
}
I have mentioned echo 'yes' and echo 'no' but both are not displaying. How to correct it
Well first of all, you won't even see those echo statements, the only things that are rendered visually for an end-user to see in Yii are the "views". For my login code, which is just a little bit different from yours, after confirming authentication, my app is redirected to home page. Your custom UserIdentity file looks fine, but again, that echo statement won't even be seen. This UserIdentity file is just for performing custom user authentication behind the scenes.
In my UserController (as opposed to your AuthController), my actionLogin is:
public function actionLogin()
{
$model=new LoginForm;
// if it is ajax validation request
if(isset($_POST['ajax']) && $_POST['ajax']==='login-form')
{
echo CActiveForm::validate($model);
Yii::app()->end();
}
// collect user input data
if(isset($_POST['LoginForm']))
{
$model->attributes=$_POST['LoginForm'];
// validate user input and redirect to the previous page if valid
if($model->validate() && $model->login())
{
$this->redirect(Yii::app()->user->returnUrl);
}
}
$this->render('/user/login',array('model'=>$model));
}
From the above, for example, you could redirect to the previous page you were at or redirect to your main site view at "/site/index" and under that have some code that does some arbitrary functions or print out HTML depending on if you're logged in or not. An overly simple site view example:
<?php
/* #var $this SiteController */
if (Yii::app()->user->isGuest)
{
// Do stuff here if user is guest.
echo 'User is a guest.';
}
else
{
// Do stuff here if user is authenticated.
echo 'User is authenticated.';
}
?>